diff options
author | Romain Jobredeaux <jobredeaux@google.com> | 2022-09-08 10:07:11 -0400 |
---|---|---|
committer | Romain Jobredeaux <jobredeaux@google.com> | 2022-09-08 13:27:56 -0400 |
commit | bf11c5015e45147f77e0bfac4f3fbb00cf4df640 (patch) | |
tree | b91320c4efbc40d509071afe32f324436068dd92 | |
parent | ca807f220265d0063f234e8251ffca5e1c6cae00 (diff) | |
parent | aebca278376b63c9c07296c9aa052845e0c1fe2a (diff) | |
download | bazelbuild-kotlin-rules-main-16k.tar.gz |
Initial merge of kotlin rules remote-tracking branch 'aosp/upstream-main'.main-16k
Change-Id: I00d5acb3726073c05cdd79f5d7adb19ae868d610
Test: added manual target to CI
Bug: 186462641
158 files changed, 9661 insertions, 0 deletions
diff --git a/.bazeliskrc b/.bazeliskrc new file mode 100644 index 0000000..1797a0f --- /dev/null +++ b/.bazeliskrc @@ -0,0 +1,15 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +USE_BAZEL_VERSION=5.1.0 @@ -0,0 +1,23 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This the official list of authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. + +# Names should be added to this file as: +# Name or Organization <email address> +# The email address is not required for organizations. + +Google LLC @@ -0,0 +1,24 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +licenses(["notice"]) + +exports_files(["LICENSE"]) + +package_group( + name = "internal", + packages = [ + "//...", + ], +) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..8557c96 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,55 @@ +<!-- + Copyright 2022 Google LLC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the License); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +Want to contribute? Great! First, read this page (including the small print at +the end). + +### Before you contribute +**Before we can use your code, you must sign the +[Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual?csw=1) +(CLA)**, which you can do online. + +The CLA is necessary mainly because you own the copyright to your changes, +even after your contribution becomes part of our codebase, so we need your +permission to use and distribute your code. We also need to be sure of +various other things — for instance that you'll tell us if you know that +your code infringes on other people's patents. You don't have to sign +the CLA until after you've submitted your code for review and a member has +approved it, but you must do it before we can put your code into our codebase. + +### The small print +Contributions made by corporations are covered by a different agreement than +the one above, the +[Software Grant and Corporate Contributor License Agreement](https://cla.developers.google.com/about/google-corporate). + +### Contribution process + +1. Explain your idea and discuss your plan with members of the team. The best + way to do this is to create + an [issue](https://github.com/bazelbuild/rules_kotlin/issues) or comment on + an existing issue. +1. Prepare a git commit with your change. Don't forget to + add [tests](https://github.com/bazelbuild/rules_kotlin/tree/main/tests). + Run the existing tests with `bazel test //...`. Update + [README.md](https://github.com/bazelbuild/rules_kotlin/blob/main/README.md) + if appropriate. +1. [Create a pull request](https://help.github.com/articles/creating-a-pull-request/). + This will start the code review process. **All submissions, including + submissions by project members, require review.** +1. You may be asked to make some changes. You'll also need to sign the CLA at + this point, if you haven't done so already. Our continuous integration bots + will test your change automatically on supported platforms. Once everything + looks good, your change will be merged. diff --git a/CONTRIBUTORS b/CONTRIBUTORS new file mode 100644 index 0000000..de2c925 --- /dev/null +++ b/CONTRIBUTORS @@ -0,0 +1,31 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# People who have agreed to one of the CLAs and can contribute patches. +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, Google employees are listed here +# but not in AUTHORS, because Google holds the copyright. +# +# https://developers.google.com/open-source/cla/individual +# https://developers.google.com/open-source/cla/corporate +# +# Names should be added to this file as: +# Name <email address> +Beth Cutler <bcutler@google.com> +Daniel Whang <djwhang@google.com> +Kevin Bierhoff <kmb@google.com> +Stefan Ramsauer <str@google.com> +Tim Peut <timpeut@google.com> +Thomas Knych <thomaswk@google.com> + @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/METADATA b/METADATA new file mode 100644 index 0000000..5d59256 --- /dev/null +++ b/METADATA @@ -0,0 +1,18 @@ +name: "bazelbuild-kotlin-rules" +description: + "A repository of [Bazel](https://bazel.build) starlark rules and tooling " + "for Kotlin. " + " " + "These rules are maintained and published by Google as-is, with limited to " + "no support available at the moment." + +third_party { + url { + type: GIT + value: "https://team.googlesource.com/kotlin-rules/rules" + } + version: "aebca278376b63c9c07296c9aa052845e0c1fe2a" + last_upgrade_date { year: 2022 month: 9 day: 7 } + license_type: NOTICE +} + diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/MODULE_LICENSE_APACHE2 @@ -0,0 +1,2 @@ +include platform/build/bazel:/OWNERS + diff --git a/README.md b/README.md new file mode 100644 index 0000000..1310a62 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +<!-- + Copyright 2022 Google LLC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the License); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +A repository of [Bazel](https://bazel.build) starlark rules and tooling for +Kotlin. + +These rules are maintained and published by Google as-is, with limited to no +support available at the moment.
\ No newline at end of file diff --git a/WORKSPACE b/WORKSPACE new file mode 100644 index 0000000..12281f1 --- /dev/null +++ b/WORKSPACE @@ -0,0 +1,108 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +workspace(name = "rules_kotlin") + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "rules_jvm_external", + strip_prefix = "rules_jvm_external-4.2", + sha256 = "cd1a77b7b02e8e008439ca76fd34f5b07aecb8c752961f9640dea15e9e5ba1ca", + url = "https://github.com/bazelbuild/rules_jvm_external/archive/4.2.zip", +) +load("@rules_jvm_external//:repositories.bzl", "rules_jvm_external_deps") +rules_jvm_external_deps() +load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup") +rules_jvm_external_setup() +load("@rules_jvm_external//:defs.bzl", "maven_install") + +http_archive( + name = "bazel_skylib", + sha256 = "f7be3474d42aae265405a592bb7da8e171919d74c16f082a5457840f06054728", + urls = [ + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.2.1/bazel-skylib-1.2.1.tar.gz", + ], +) +load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") +bazel_skylib_workspace() + +http_archive( + name = "bazel_platforms", + sha256 = "379113459b0feaf6bfbb584a91874c065078aa673222846ac765f86661c27407", + urls = [ + "https://github.com/bazelbuild/platforms/releases/download/0.0.5/platforms-0.0.5.tar.gz", + ], +) + +http_archive( + name = "rules_java", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/rules_java/releases/download/5.0.0/rules_java-5.0.0.tar.gz", + "https://github.com/bazelbuild/rules_java/releases/download/5.0.0/rules_java-5.0.0.tar.gz", + ], + sha256 = "8c376f1e4ab7d7d8b1880e4ef8fc170862be91b7c683af97ca2768df546bb073", +) +load("@rules_java//java:repositories.bzl", "java_tools_repos") +java_tools_repos() + +http_archive( + name = "dagger", + strip_prefix = "dagger-dagger-2.28.1", + build_file = "@//bazel:dagger.BUILD", + sha256 = "9e69ab2f9a47e0f74e71fe49098bea908c528aa02fa0c5995334447b310d0cdd", + urls = ["https://github.com/google/dagger/archive/dagger-2.28.1.zip"], +) +load("@dagger//:workspace_defs.bzl", "DAGGER_ARTIFACTS", "DAGGER_REPOSITORIES") + +load("@//toolchains/kotlin_jvm:kt_jvm_toolchains.bzl", "KT_VERSION") +http_archive( + name = "kotlinc", + build_file = "@//bazel:kotlinc.BUILD", + sha256 = "7683f5451ef308eb773a686ee7779a76a95ed8b143c69ac247937619d7ca3a09", + strip_prefix = "kotlinc", + urls = [ + "https://github.com/JetBrains/kotlin/releases/download/v{0}/kotlin-compiler-{0}.zip".format(KT_VERSION[1:].replace("_", ".")), + ], +) + +register_toolchains("@//toolchains/kotlin_jvm:all") + +maven_install( + artifacts = DAGGER_ARTIFACTS + [ + "com.google.auto.service:auto-service-annotations:1.0.1", + "com.google.auto.service:auto-service:1.0.1", + "com.google.auto.value:auto-value:1.9", + "com.google.testing.compile:compile-testing:0.19", + "com.google.truth:truth:1.1.3", + "javax.inject:jsr330-api:0.9", + "junit:junit:4.13.2", + "org.jacoco:org.jacoco.agent:0.8.8", + "org.jacoco:org.jacoco.cli:0.8.8", + "org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.4.2", + "org.mockito:mockito-core:4.5.1", + ], + repositories = DAGGER_REPOSITORIES + [ + "https://repository.mulesoft.org/nexus/content/repositories/public", + ], + override_targets = { + "org.jetbrains.kotlin:annotations": "@kotlinc//:annotations", + "org.jetbrains.kotlin:kotlin-reflect": "@kotlinc//:kotlin_reflect", + "org.jetbrains.kotlin:kotlin-stdlib": "@kotlinc//:kotlin_stdlib", + "org.jetbrains.kotlin:kotlin-stdlib-jdk7": "@kotlinc//:kotlin_stdlib_jdk7", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8": "@kotlinc//:kotlin_stdlib_jdk8", + "org.jetbrains.kotlin:kotlin-test": "@kotlinc//:kotlin_test", + }, +) + diff --git a/bazel/BUILD b/bazel/BUILD new file mode 100644 index 0000000..e10757f --- /dev/null +++ b/bazel/BUILD @@ -0,0 +1,42 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +licenses(["notice"]) # Apache 2.0 + +package(default_visibility = ["//:internal"]) + +java_library( + name = "auto_service", + exported_plugins = [":auto_service_plugin"], + exports = ["@maven//:com_google_auto_service_auto_service_annotations"], +) + +java_plugin( + name = "auto_service_plugin", + processor_class = "com.google.auto.service.processor.AutoServiceProcessor", + visibility = ["//visibility:private"], + deps = ["@maven//:com_google_auto_service_auto_service"], +) + +java_plugin( + name = "auto_value_plugin", + processor_class = "com.google.auto.value.processor.AutoValueProcessor", + deps = ["@maven//:com_google_auto_value_auto_value"], +) + +java_binary( + name = "jacoco_cli", + main_class = "org.jacoco.cli.internal.Main", + runtime_deps = ["@maven//:org_jacoco_org_jacoco_cli"], +) diff --git a/bazel/clang_llvm_darwin_macos.BUILD b/bazel/clang_llvm_darwin_macos.BUILD new file mode 100644 index 0000000..10a2a72 --- /dev/null +++ b/bazel/clang_llvm_darwin_macos.BUILD @@ -0,0 +1,19 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +exports_files(["bin/llvm-lto"]) diff --git a/bazel/clang_llvm_linux_x86_64.BUILD b/bazel/clang_llvm_linux_x86_64.BUILD new file mode 100644 index 0000000..588c047 --- /dev/null +++ b/bazel/clang_llvm_linux_x86_64.BUILD @@ -0,0 +1,31 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +exports_files([ + "bin/clang", + "bin/clang++", + "bin/llvm-lto", + "lib/libclang.so", +]) + +filegroup( + name = "libs", + srcs = glob([ + "lib/*.a", + ]), +) diff --git a/bazel/dagger.BUILD b/bazel/dagger.BUILD new file mode 100644 index 0000000..76c0738 --- /dev/null +++ b/bazel/dagger.BUILD @@ -0,0 +1,17 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("@dagger//:workspace_defs.bzl", "dagger_rules") + +dagger_rules() diff --git a/bazel/gcc_toolchain_linux_x86_64.BUILD b/bazel/gcc_toolchain_linux_x86_64.BUILD new file mode 100644 index 0000000..f1d1734 --- /dev/null +++ b/bazel/gcc_toolchain_linux_x86_64.BUILD @@ -0,0 +1,45 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +filegroup( + name = "sysroot_crt_files", + srcs = [ + "x86_64-unknown-linux-gnu/sysroot/usr/lib/crt1.o", + "x86_64-unknown-linux-gnu/sysroot/usr/lib/crti.o", + "x86_64-unknown-linux-gnu/sysroot/usr/lib/crtn.o", + ], +) + +filegroup( + name = "libgcc_crt_files", + srcs = [ + "lib/gcc/x86_64-unknown-linux-gnu/4.8.5/crtbegin.o", + "lib/gcc/x86_64-unknown-linux-gnu/4.8.5/crtend.o", + ], +) + +filegroup( + name = "libs", + srcs = glob([ + "lib/gcc/x86_64-unknown-linux-gnu/4.8.5/*.a", + "x86_64-unknown-linux-gnu/sysroot/lib/*.a", + "x86_64-unknown-linux-gnu/sysroot/usr/lib/*.a", + "x86_64-unknown-linux-gnu/sysroot/lib/*.so*", + "x86_64-unknown-linux-gnu/sysroot/usr/lib/*.so*", + ]), +) diff --git a/bazel/kotlin_native_linux_x86_64.BUILD b/bazel/kotlin_native_linux_x86_64.BUILD new file mode 100644 index 0000000..1c249ac --- /dev/null +++ b/bazel/kotlin_native_linux_x86_64.BUILD @@ -0,0 +1,35 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +java_import( + name = "konan_import", + jars = glob( + ["konan/lib/*.jar"], + ), +) + +filegroup( + name = "konan_runfiles", + srcs = glob( + [ + "klib/common/**/*", + "konan/**", + ], + exclude = ["konan/lib/*.jar"], + ), +) diff --git a/bazel/kotlin_native_macos.BUILD b/bazel/kotlin_native_macos.BUILD new file mode 100644 index 0000000..1c249ac --- /dev/null +++ b/bazel/kotlin_native_macos.BUILD @@ -0,0 +1,35 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +java_import( + name = "konan_import", + jars = glob( + ["konan/lib/*.jar"], + ), +) + +filegroup( + name = "konan_runfiles", + srcs = glob( + [ + "klib/common/**/*", + "konan/**", + ], + exclude = ["konan/lib/*.jar"], + ), +) diff --git a/bazel/kotlinc.BUILD b/bazel/kotlinc.BUILD new file mode 100644 index 0000000..822d876 --- /dev/null +++ b/bazel/kotlinc.BUILD @@ -0,0 +1,83 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package(default_visibility = ["//visibility:public"]) + +java_import( + name = "annotations", + jars = ["lib/annotations-13.0.jar"], +) + +java_import( + name = "jvm_abi_gen_plugin", + jars = ["lib/jvm-abi-gen.jar"], +) + +java_import( + name = "kotlin_annotation_processing", + jars = ["lib/kotlin-annotation-processing.jar"], +) + +sh_binary( + name = "kotlin_compiler", + srcs = ["bin/kotlinc"], + data = glob(["lib/**"]), +) + +# java_binary( +# name = "kotlin_compiler", +# main_class = "org.jetbrains.kotlin.cli.jvm.K2JVMCompiler", +# runtime_deps = [":kotlin_compiler_lib"], +# ) + +# java_import( +# name = "kotlin_compiler_lib", +# jars = ["lib/kotlin-compiler.jar"] +# srcjar = "lib/kotlin-compiler-sources.jar", +# ) + +java_import( + name = "kotlin_reflect", + jars = ["lib/kotlin-reflect.jar"], + srcjar = "lib/kotlin-reflect-sources.jar", +) + +java_import( + name = "kotlin_stdlib", + jars = ["lib/kotlin-stdlib.jar"], + srcjar = "lib/kotlin-stdlib-sources.jar", +) + +java_import( + name = "kotlin_stdlib_jdk7", + jars = ["lib/kotlin-stdlib-jdk7.jar"], + srcjar = "lib/kotlin-stdlib-jdk7-sources.jar", +) + +java_import( + name = "kotlin_stdlib_jdk8", + jars = ["lib/kotlin-stdlib-jdk8.jar"], + srcjar = "lib/kotlin-stdlib-jdk8-sources.jar", +) + +java_import( + name = "kotlin_test", + jars = ["lib/kotlin-test.jar"], + srcjar = "lib/kotlin-test-sources.jar", +) + +alias( + name = "kotlin_test_not_testonly", + actual = ":kotlin_test", +) diff --git a/bazel/stubs.bzl b/bazel/stubs.bzl new file mode 100644 index 0000000..d948cc8 --- /dev/null +++ b/bazel/stubs.bzl @@ -0,0 +1,34 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Stubs""" + +load("@bazel_skylib//lib:sets.bzl", "sets") + +def register_extension_info(**_kwargs): + pass + +FORBIDDEN_DEP_PACKAGES = sets.make([]) + +EXEMPT_DEPS = sets.make([]) + +DEFAULT_BUILTIN_PROCESSORS = [ + "com.google.android.apps.play.store.plugins.injectionentrypoint.InjectionEntryPointProcessor", + "com.google.android.apps.play.store.plugins.interfaceaggregator.InterfaceAggregationProcessor", + "com.google.auto.factory.processor.AutoFactoryProcessor", + "dagger.android.processor.AndroidProcessor", + "dagger.internal.codegen.ComponentProcessor", +] + +BASE_JVMOPTS = [] diff --git a/kokoro/presubmit.cfg b/kokoro/presubmit.cfg new file mode 100644 index 0000000..07e57e4 --- /dev/null +++ b/kokoro/presubmit.cfg @@ -0,0 +1,32 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# -*- protobuffer -*- +# proto-message: BuildConfig + +# The version of bazel to use to test the rules_kotlin. +# Update this as newer versions of bazel are released. +build_params { + key: "bazel_version" + value: "5.1.0" +} + +env_vars { + key: "bazel_version" + value: "$[bazel_version]" +} + +gfile_resources: "/x20/teams/bazel/releases/bazel-$[bazel_version]-linux-x86_64" + +build_file: "presubmit/kokoro/presubmit.sh" diff --git a/kokoro/presubmit.sh b/kokoro/presubmit.sh new file mode 100755 index 0000000..716cb86 --- /dev/null +++ b/kokoro/presubmit.sh @@ -0,0 +1,54 @@ +#!/bin/bash -e +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# DO NOT SET -x. It will leak any secret credentials into logs. + +kokoro_scm_name="presubmit" +workspace_root="${KOKORO_ARTIFACTS_DIR}/git/${kokoro_scm_name}" + +bazel="${KOKORO_GFILE_DIR}/bazel-${bazel_version}-linux-x86_64" +chmod +x "$bazel" + +# Default JDK on GCP_UBUNTU is JDK8 +sudo update-java-alternatives --set java-1.11.0-openjdk-amd64 +# Bazel reads JAVA_HOME +export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64/ + +# Create a tmpfs in the sandbox at "/tmp/hsperfdata_$USERNAME" to avoid the +# problems described in https://github.com/bazelbuild/bazel/issues/3236 +# Basically, the JVM creates a file at /tmp/hsperfdata_$USERNAME/$PID, but +# processes all get a PID of 2 in the sandbox, so concurrent Java build actions +# could crash because they're trying to modify the same file. So, tell the +# sandbox to mount a tmpfs at /tmp/hsperfdata_$(whoami) so that each JVM gets +# its own version of that directory. +hsperfdata_dir="/tmp/hsperfdata_$(whoami)_rules_kotlin" +mkdir -p "$hsperfdata_dir" + +cd "${workspace_root}" +"$bazel" test \ + --sandbox_tmpfs_path="$hsperfdata_dir" \ + --verbose_failures \ + --experimental_google_legacy_api \ + //tests/... + +# Testing with code coverage +"$bazel" test \ + --sandbox_tmpfs_path="$hsperfdata_dir" \ + --verbose_failures \ + --experimental_google_legacy_api \ + --collect_code_coverage=1 \ + //tests/analysis:kt_jvm_compile_using_kt_jvm_compile_with_r_java_test \ + //tests/analysis:kt_jvm_compile_with_r_java_as_first_dep_test \ + //tests/analysis:kt_jvm_compile_without_srcs_and_with_exports_test
\ No newline at end of file diff --git a/kotlin/BUILD b/kotlin/BUILD new file mode 100644 index 0000000..5cc7a19 --- /dev/null +++ b/kotlin/BUILD @@ -0,0 +1,15 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +licenses(["notice"]) # Apache 2.0 diff --git a/kotlin/common.bzl b/kotlin/common.bzl new file mode 100644 index 0000000..3ffc660 --- /dev/null +++ b/kotlin/common.bzl @@ -0,0 +1,1169 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Common Kotlin definitions.""" + +load("@bazel_skylib//lib:sets.bzl", "sets") +load("@bazel_skylib//lib:structs.bzl", "structs") +load("//bazel:stubs.bzl", "BASE_JVMOPTS") +load("//bazel:stubs.bzl", "DEFAULT_BUILTIN_PROCESSORS") + +# TODO: Remove the _ALLOWED_*_RULES lists to determine which rules +# are accepted dependencies to Kotlin rules as the approach does not scale +# because it will require a cl + release for every new rule. + +_ALLOWED_ANDROID_RULES = [ + "aar_import", + "android_library", + "kt_android_library_helper", +] + +_ALLOWED_JVM_RULES = [ + "_java_grpc_library", + "_java_lite_grpc_library", + "af_internal_guice_module", # b/142743220 + "af_internal_jbcsrc_library", # added with b/143872075 + "af_internal_soyinfo_generator", # b/143872075 + "java_import", + "java_library", + "java_lite_proto_library", + "java_mutable_proto_library", + "java_proto_library", + "java_wrap_cc", # b/152799927 + "jvm_import", + "kt_grpc_library_helper", + "kt_jvm_library_helper", + "kt_jvm_import", + "kt_proto_library_helper", + "_j2kt_jvm_library_rule", # b/233055549 +] + +_EXT = struct( + KT = ".kt", + JAVA = ".java", + JAR = ".jar", + SRCJAR = ".srcjar", +) + +_KT_FILE_TYPES = [_EXT.KT] + +_KT_JVM_FILE_TYPES = [ + _EXT.JAVA, + _EXT.KT, + _EXT.SRCJAR, +] + +_JAR_FILE_TYPE = [_EXT.JAR] + +_SRCJAR_FILE_TYPES = [_EXT.JAR, _EXT.SRCJAR] + +_RULE_FAMILY = struct( + UNKNOWN = 0, + JVM_LIBRARY = 1, + ANDROID_LIBRARY = 2, +) + +def _is_dir(file, basename): + return file.is_directory and file.basename == basename + +def _is_kt_src(src): + """Decides if `src` Kotlin code. + + Either: + - a Kotlin source file + - a tree-artifact expected to contain only Kotlin source files + """ + + return src.path.endswith(_EXT.KT) or _is_dir(src, "kotlin") + +# Compute module name based on target (b/139403883), similar to Swift +def _derive_module_name(ctx): + label = _get_original_kt_target_label(ctx) + package_part = label.package.replace("/", ".") # .package has no leading '//' + name_part = label.name + if package_part: + return package_part + "_" + name_part + return name_part + +def _common_kapt_and_kotlinc_args(ctx, toolchain): + return toolchain.kotlinc_cli_flags + [ + # Set module name so module-level metadata is preserved when merging Jars (b/139403883) + "-module-name", + _derive_module_name(ctx), + ] + +# Runs KAPT in two separate actions so annotation processors only rerun when Kotlin stubs changed. +def _kapt( + ctx, + kt_srcs = [], + common_srcs = [], + java_srcs = [], + kotlincopts = [], + plugin_processors = [], + plugin_classpaths = None, + plugin_data = None, + javacopts = [], + toolchain = None, + classpath = []): + """Runs annotation processors, returns directory containing generated sources.""" + if not plugin_processors: # shouldn't get here + fail("Kapt cannot work without processors") + + # Kapt fails with "no source files" if only given Java sources (b/110473479), so skip ahead to + # just run turbine if there are no .kt sources. + stub_srcjars = [] + if kt_srcs or common_srcs: + stubs_dir = ctx.actions.declare_directory(ctx.label.name + "/kapt/gen/stubs") + _kapt_stubs( + ctx, + stubs_dir, + kt_srcs, + common_srcs, + java_srcs, + kotlincopts, + plugin_processors, + plugin_classpaths, + toolchain, + classpath, + ) + + # Create a srcjar for the .java stubs generated by kapt, + # mostly to filter out non-.java stub outputs, e.g. .kapt_metadata. + stub_srcjars.append(_create_jar( + ctx, + toolchain.jar_tool, + ctx.actions.declare_file("stubs-srcjar.jar", sibling = stubs_dir), + [stubs_dir], + file_extensions = ["java"], + )) + + output_jar = ctx.actions.declare_file(ctx.label.name + "-kapt.jar") + output_srcjar = ctx.actions.declare_file(ctx.label.name + "-kapt.srcjar") + output_manifest = ctx.actions.declare_file(ctx.label.name + "-kapt.jar_manifest_proto") + _run_turbine( + ctx, + toolchain, + plugin_processors, + plugin_classpaths, + plugin_data, + classpath, + javacopts, + java_srcs, + output_jar, + output_srcjar, + output_manifest, + stub_srcjars, + ) + + return struct( + jar = output_jar, + manifest = output_manifest, + srcjar = output_srcjar, + ) + +def _kapt_stubs( + ctx, + stubs_dir, + kt_srcs = [], + common_srcs = [], + java_srcs = [], + kotlincopts = [], + plugin_processors = [], + plugin_classpaths = None, + toolchain = None, + classpath = []): + """Runs kapt3's "stubs" mode to generate .java stubs from given .kt sources.""" + + # Use params file to handle long classpaths (b/76185759). + kaptargs = ctx.actions.args() + kaptargs.use_param_file("@%s", use_always = True) + kaptargs.set_param_file_format("multiline") # avoid shell-quoting which breaks workers + + kaptargs.add(toolchain.kotlin_annotation_processing, format = "-Xplugin=%s") + kaptargs.add("-P", "plugin:org.jetbrains.kotlin.kapt3:aptMode=stubs") + + # List processor classes one by one (comma-separated list doesn't work even though documentation + # seems to say that it should: http://kotlinlang.org/docs/reference/kapt.html#using-in-cli) + kaptargs.add_all( + plugin_processors, + before_each = "-P", + format_each = "plugin:org.jetbrains.kotlin.kapt3:processors=%s", + uniquify = True, # multiple plugins can define the same processor, theoretically + ) + kaptargs.add_all( + plugin_classpaths, # no need to uniquify depsets + before_each = "-P", + format_each = "plugin:org.jetbrains.kotlin.kapt3:apclasspath=%s", + ) + kaptargs.add("-P", "plugin:org.jetbrains.kotlin.kapt3:sources=/tmp") + kaptargs.add("-P", "plugin:org.jetbrains.kotlin.kapt3:classes=/tmp") + kaptargs.add("-P", stubs_dir.path, format = "plugin:org.jetbrains.kotlin.kapt3:stubs=%s") + kaptargs.add("-P", "plugin:org.jetbrains.kotlin.kapt3:correctErrorTypes=true") + + # kapt requires javac options to be base64-encoded, + # see: http://kotlinlang.org/docs/reference/kapt.html#apjavac-options-encoding + # The string below is the encoding of "-source 8 -target 8". + # TODO: use the full google3 defaults instead of hard-coding. + kaptargs.add("-P", "plugin:org.jetbrains.kotlin.kapt3:javacArguments=rO0ABXccAAAAAgAHLXNvdXJjZQABOAAHLXRhcmdldAABOA") + kaptargs.add_all(_common_kapt_and_kotlinc_args(ctx, toolchain)) + kaptargs.add_joined("-cp", classpath, join_with = ":") + kaptargs.add_all(kotlincopts) + + kaptargs.add_all(kt_srcs) + kaptargs.add_all(common_srcs) + if java_srcs: + kaptargs.add_all(java_srcs) + + tool_inputs = [toolchain.kotlin_annotation_processing] + + ctx.actions.run( + executable = toolchain.kotlin_compiler, + arguments = [kaptargs], + inputs = depset( + direct = ( + kt_srcs + + common_srcs + + java_srcs + + tool_inputs + ), + transitive = [ + classpath, + plugin_classpaths, + ], + ), + outputs = [stubs_dir], + mnemonic = "KtKaptStubs", + progress_message = "Kapt stubs generation: %s" % _get_original_kt_target_label(ctx), + execution_requirements = { + "worker-key-mnemonic": "Kt2JavaCompile", # share workers with Kt2JavaCompile (b/179578322) + }, + ) + +def _run_turbine( + ctx, + toolchain, + plugin_processors, + plugin_classpaths, + plugin_data, + classpath, + javacopts, + java_srcs, + output_jar, + output_srcjar, + output_manifest, + stub_srcjar = []): + turbineargs = ctx.actions.args() + turbineargs.use_param_file("@%s") + turbineargs.add_all("--processors", plugin_processors) + turbineargs.add_all("--processorpath", plugin_classpaths) + + # --define=header_compiler_builtin_processors_setting=false should disable built-in processors, + # see: http://google3/tools/jdk/BUILD?l=338&rcl=269833772 + enable_builtin_processors = ctx.var.get("header_compiler_builtin_processors_setting", default = "true") != "false" + if enable_builtin_processors: + turbineargs.add_all("--builtin_processors", DEFAULT_BUILTIN_PROCESSORS) + + turbineargs.add_all("--javacopts", javacopts) + turbineargs.add("--") + + turbineargs.add_all("--classpath", classpath) + + turbineargs.add("--gensrc_output", output_srcjar) + turbineargs.add("--resource_output", output_jar) + turbineargs.add("--output_manifest_proto", output_manifest) + + turbineargs.add_all("--source_jars", stub_srcjar) + + if java_srcs: + turbineargs.add("--sources") + turbineargs.add_all(java_srcs) + + outputs = [output_srcjar, output_jar, output_manifest] + progress_message = "Kotlin annotation processing: %s %s" % (_get_original_kt_target_label(ctx), ", ".join(plugin_processors)) + inputs = depset(direct = java_srcs + stub_srcjar, transitive = [classpath, plugin_classpaths, plugin_data]) + + if enable_builtin_processors and toolchain.turbine_direct and all([p in DEFAULT_BUILTIN_PROCESSORS for p in plugin_processors]): + ctx.actions.run( + executable = toolchain.turbine_direct, + arguments = [turbineargs], + inputs = inputs, + outputs = outputs, + mnemonic = "KtKaptAptDirect", + progress_message = progress_message, + ) + else: + _actions_run_deploy_jar( + ctx = ctx, + java_runtime = toolchain.java_runtime, + deploy_jar = toolchain.turbine, + deploy_jsa = toolchain.turbine_jsa, + inputs = inputs, + outputs = outputs, + args = [turbineargs], + mnemonic = "KtKaptApt", + progress_message = progress_message, + ) + +def _derive_gen_class_jar( + ctx, + toolchain, + manifest_proto, + javac_jar, + java_srcs = []): + """Returns the annotation processor-generated classes contained in given Jar.""" + if not manifest_proto: + return None + if not javac_jar: + fail("There must be a javac Jar if there was annotation processing") + if not java_srcs: + # If there weren't any hand-written .java srcs, just use Javac's output + return javac_jar + + # Run GenClass tool to derive gen_class_jar by filtering hand-written sources. + # cf. Bazel's JavaCompilationHelper#createGenJarAction + result = ctx.actions.declare_file(ctx.label.name + "-gen.jar") + + genclass_args = ctx.actions.args() + genclass_args.add("--manifest_proto", manifest_proto) + genclass_args.add("--class_jar", javac_jar) + genclass_args.add("--output_jar", result) + + _actions_run_deploy_jar( + ctx = ctx, + java_runtime = toolchain.java_runtime, + deploy_jar = toolchain.genclass, + inputs = [manifest_proto, javac_jar], + outputs = [result], + args = [genclass_args], + mnemonic = "KtGenClassJar", + progress_message = "Deriving %{output}", + ) + + return result + +def _kt_plugins_map( + java_plugin_infos = [], + kt_compiler_plugin_infos = []): + """A struct containing all the plugin types understood by rules_kotlin. + + Args: + java_plugin_infos: (list[JavaPluginInfo]) + kt_compiler_plugin_infos: (list[KtCompilerPluginInfo]) + """ + return struct( + java_plugin_infos = java_plugin_infos, + kt_compiler_plugin_infos = kt_compiler_plugin_infos, + ) + +def _run_kotlinc( + ctx, + output, + kt_srcs = [], + common_srcs = [], + java_srcs_and_dirs = [], + kotlincopts = [], + compile_jdeps = depset(), + toolchain = None, + classpath = [], + directdep_jars = depset(), + plugins = _kt_plugins_map(), + friend_jars = depset(), + enforce_strict_deps = False, + enforce_complete_jdeps = False): + if output.extension != "jar": + fail("Expect to output a Jar but got %s" % output) + + direct_inputs = [] + transitive_inputs = [] + outputs = [] + + # Args to kotlinc. + # + # These go at the end of the commandline. They should be passed through all wrapper + # layers without post-processing, except to unpack param files. + kotlinc_args = ctx.actions.args() + kotlinc_args.use_param_file("@%s", use_always = True) # Use params file to handle long classpaths (b/76185759) + kotlinc_args.set_param_file_format("multiline") # kotlinc only supports double-quotes ("): https://youtrack.jetbrains.com/issue/KT-24472 + + kotlinc_args.add_all(_common_kapt_and_kotlinc_args(ctx, toolchain)) + kotlinc_args.add_joined("-cp", classpath, join_with = ":") + transitive_inputs.append(classpath) + kotlinc_args.add_all(kotlincopts) + + kotlinc_args.add(toolchain.jvm_abi_gen_plugin, format = "-Xplugin=%s") + direct_inputs.append(toolchain.jvm_abi_gen_plugin) + kt_ijar = ctx.actions.declare_file(output.basename[:-4] + "-ijar.jar", sibling = output) + kotlinc_args.add("-P", kt_ijar, format = "plugin:org.jetbrains.kotlin.jvm.abi:outputDir=%s") + outputs.append(kt_ijar) + + for p in plugins.kt_compiler_plugin_infos: + kotlinc_args.add(p.jar, format = "-Xplugin=%s") + direct_inputs.append(p.jar) + kotlinc_args.add_all(p.args, before_each = "-P") + + # Common sources must also be specified as -Xcommon-sources= in addition to appearing in the + # source list. + if common_srcs: + kotlinc_args.add("-Xmulti-platform=true") + kotlinc_args.add_all(common_srcs, format_each = "-Xcommon-sources=%s") + direct_inputs.extend(common_srcs) + + kotlinc_args.add("-d", output) + outputs.append(output) + kotlinc_args.add_all(kt_srcs) + direct_inputs.extend(kt_srcs) + kotlinc_args.add_all(common_srcs) + direct_inputs.extend(common_srcs) + + if java_srcs_and_dirs: + # This expands any directories into their contained files + kotlinc_args.add_all(java_srcs_and_dirs) + direct_inputs.extend(java_srcs_and_dirs) + + kotlinc_args.add_joined(friend_jars, format_joined = "-Xfriend-paths=%s", join_with = ",") + transitive_inputs.append(friend_jars) + + # Do not change the "shape" or mnemonic of this action without consulting Kythe team + # (kythe-eng@), to avoid breaking the Kotlin Kythe extractor which "shadows" this action. In + # particular, the extractor expects this to be a vanilla "spawn" (ctx.actions.run) so don't + # change this to ctx.actions.run_shell or something else without considering Kythe implications + # (b/112439843). + ctx.actions.run( + executable = toolchain.kotlin_compiler, + arguments = [kotlinc_args], + inputs = depset(direct = direct_inputs, transitive = transitive_inputs), + outputs = outputs, + mnemonic = "Kt2JavaCompile", + progress_message = "Compiling Kotlin For Java Runtime: %s" % _get_original_kt_target_label(ctx), + execution_requirements = { + "worker-key-mnemonic": "Kt2JavaCompile", + }, + ) + + # TODO: Normalize paths to match package declarations in source files. + srcjar = _create_jar( + ctx, + toolchain.jar_tool, + ctx.actions.declare_file(ctx.label.name + "-kt-src.jar"), + kt_srcs + common_srcs, + ) + + return struct( + output_jar = output, + compile_jar = kt_ijar, + source_jar = srcjar, + ) + +def _get_original_kt_target_label(ctx): + label = ctx.label + if label.name.find("_DO_NOT_DEPEND") > 0: + # Remove rule suffix added by kt_android_library + label = label.relative(":%s" % label.name[0:label.name.find("_DO_NOT_DEPEND")]) + + return label + +def _check_deps( + ctx, + jars_to_check = [], + merged_deps = None, + enforce_strict_deps = True, + jdeps_output = None, + deps_checker = None, + java_toolchain = None): + # Direct compile_jars before transitive not to confuse strict_deps (b/149107867) + full_classpath = depset( + order = "preorder", + transitive = [merged_deps.compile_jars, merged_deps.transitive_compile_time_jars], + ) + label = _get_original_kt_target_label(ctx) + bootclasspath = java_toolchain.bootclasspath + + args = ctx.actions.args() + args.add("--jdeps_output", jdeps_output) + args.add_all(jars_to_check, before_each = "--input") + args.add_all(bootclasspath, before_each = "--bootclasspath_entry") + args.add_all(full_classpath, before_each = "--classpath_entry") + if enforce_strict_deps: + args.add_all(merged_deps.compile_jars, before_each = "--directdep") + args.add("--checking_mode=%s" % ("error" if enforce_strict_deps else "silence")) + args.add("--nocheck_missing_members") # compiler was happy so no need + args.add("--rule_label") + args.add(label) + + ctx.actions.run( + executable = deps_checker, + arguments = [args], + inputs = depset( + jars_to_check, + transitive = [bootclasspath, full_classpath], + ), + outputs = [jdeps_output], + mnemonic = "KtCheckStrictDeps" if enforce_strict_deps else "KtJdeps", + progress_message = "%s deps for %s" % ( + "Checking strict" if enforce_strict_deps else "Computing", + label, + ), + ) + +def _offline_instrument_jar(ctx, toolchain, jar, srcs = []): + paths_for_coverage_file = ctx.actions.declare_file(ctx.label.name + "-kt-paths-for-coverage.txt") + paths = ctx.actions.args() + paths.set_param_file_format("multiline") # don't shell-quote, just list file names + paths.add_all([src for src in srcs if src.is_source]) + ctx.actions.write(paths_for_coverage_file, paths) + + result = ctx.actions.declare_file(ctx.label.name + "-instrumented.jar") + args = ctx.actions.args() + args.add(jar) + args.add(result) + args.add(paths_for_coverage_file) + ctx.actions.run( + executable = toolchain.coverage_instrumenter, + arguments = [args], + inputs = [jar, paths_for_coverage_file], + outputs = [result], + mnemonic = "KtJaCoCoInstrument", + progress_message = "Instrumenting Kotlin for coverage collection: %s" % _get_original_kt_target_label(ctx), + ) + + return result + +def _singlejar( + ctx, + inputs, + output, + singlejar, + mnemonic = "KtMergeJar", + content = "final Jar", + preserve_compression = False, + pseudo_inputs = []): + label = _get_original_kt_target_label(ctx) + args = ctx.actions.args() + args.add("--normalize") + args.add("--add_missing_directories") # make output more similar to jar tool (b/114414678) + args.add("--exclude_build_data") + args.add("--no_duplicates") # No Kt/Java classname collisions (b/216841985) + args.add("--output") + args.add(output) + args.add("--sources") + args.add_all(inputs) + args.add("--deploy_manifest_lines") + args.add("Target-Label: %s" % label) + if preserve_compression: + args.add("--dont_change_compression") + + ctx.actions.run( + executable = singlejar, + arguments = [args], + inputs = inputs + pseudo_inputs, + outputs = [output], + mnemonic = mnemonic, + progress_message = "Merging %s: %s" % (content, label), + ) + +def _merge_jdeps(ctx, kt_jvm_toolchain, jdeps_files, output_suffix = ""): + merged_jdeps_file = ctx.actions.declare_file(ctx.label.name + output_suffix + ".jdeps") + + args = ctx.actions.args() + args.add("--kind=jdeps") + args.add(merged_jdeps_file, format = "--output=%s") + args.add(_get_original_kt_target_label(ctx), format = "--rule_label=%s") + args.add_all(jdeps_files) + + ctx.actions.run( + executable = kt_jvm_toolchain.jdeps_merger, + inputs = jdeps_files, + outputs = [merged_jdeps_file], + arguments = [args], + mnemonic = "KtMergeJdeps", + progress_message = "Merging jdeps files %{output}", + ) + + return merged_jdeps_file + +def _expand_zip(ctx, dir, input, extra_args = []): + ctx.actions.run_shell( + outputs = [dir], + inputs = [input], + command = "unzip -q {input} -d {dir} {args} 2> /dev/null || mkdir -p {dir}".format( + input = input.path, + dir = dir.path, + args = " ".join(extra_args), + ), + ) + return dir + +def _create_jar(ctx, jar_tool, out_jar, inputs, file_extensions = None): + def file_filter(file): + return file.path if ( + file_extensions == None or (file.extension in file_extensions) + ) else None + + args = ctx.actions.args() + args.add("cf", out_jar) + args.add_all(inputs, map_each = file_filter, allow_closure = True) + + ctx.actions.run( + executable = jar_tool, + inputs = inputs, + outputs = [out_jar], + arguments = [args], + mnemonic = "KtJar", + progress_message = "Create Jar (kotlin/common.bzl): %{output}", + ) + + return out_jar + +def _create_jar_from_tree_artifacts(ctx, jar_tool, output_jar, input_dirs): + """Packs a sequence of tree artifacts into a single jar. + + Given the following file directory structure, + /usr/home/a/x/1.txt + /usr/home/b/y/1.txt + with an input_dirs as [ + "/usr/home/a", + "/usr/home/b", + ], + The tool produces a jar with in-archive structure of, + x/1.txt + y/1.txt + + The function fails on the duplicate jar entry case. e.g. if we pass an + input_dirs as [ + "/usr/home/a/x", + "/usr/home/b/y", + ], + then the blaze action would fail with an error message. + "java.util.zip.ZipException: duplicate entry: 1.txt" + + Args: + ctx: The build rule context. + jar_tool: A Unix-API-compatible jar tool. + output_jar: The jar to be produced by this action. + input_dirs: A sequence of tree artifacts to be zipped. + + Returns: + The generated output jar, i.e. output_jar + """ + + args = ctx.actions.args() + + for in_dir in input_dirs: + if not in_dir.is_directory: + fail("Expected a directory input, but got {}.".format(in_dir)) + args.add(in_dir.path) + + ctx.actions.run_shell( + command = """ + JAR_TOOL={} + OUT_JAR={} + OUT_DIR="$(dirname $OUT_JAR)" + RES_DIR=$OUT_DIR/META-INF + mkdir $RES_DIR + $JAR_TOOL cf $OUT_JAR -C $RES_DIR . + rmdir $RES_DIR + for INPUT_DIR in $@ + do + if [ -d $INPUT_DIR ] + then + $JAR_TOOL uf $OUT_JAR -C $INPUT_DIR . + fi + done + """.format(jar_tool.executable.path, output_jar.path), + arguments = [args], + inputs = input_dirs, + outputs = [output_jar], + tools = [jar_tool], + mnemonic = "KtJarActionFromTreeArtifacts", + progress_message = "Create Jar %{output}", + ) + return output_jar + +def _DirSrcjarSyncer(ctx, kt_toolchain, name): + _dirs = [] + _srcjars = [] + + def add_dirs(dirs): + if not dirs: + return + + _dirs.extend(dirs) + _srcjars.append( + _create_jar_from_tree_artifacts( + ctx, + kt_toolchain.jar_tool, + ctx.actions.declare_file( + "%s/%s%s.srcjar" % (ctx.label.name, name, len(_srcjars)), + ), + dirs, + ), + ) + + def add_srcjars(srcjars): + if not srcjars: + return + + for srcjar in srcjars: + _dirs.append( + _expand_zip( + ctx, + ctx.actions.declare_directory( + "%s/%s%s.expand" % (ctx.label.name, name, len(_dirs)), + ), + srcjar, + extra_args = ["*.java", "*.kt"], + ), + ) + _srcjars.extend(srcjars) + + return struct( + add_dirs = add_dirs, + add_srcjars = add_srcjars, + dirs = _dirs, + srcjars = _srcjars, + ) + +def _actions_run_deploy_jar( + ctx, + java_runtime, + deploy_jar, + inputs, + args = [], + deploy_jsa = None, + **kwargs): + java_args = ctx.actions.args() + java_inputs = [] + if deploy_jsa: + java_args.add("-Xshare:auto") + java_args.add(deploy_jsa, format = "-XX:SharedArchiveFile=%s") + java_args.add("-XX:-VerifySharedSpaces") + java_args.add("-XX:-ValidateSharedClassPaths") + java_inputs.append(deploy_jsa) + java_args.add("-jar", deploy_jar) + java_inputs.append(deploy_jar) + + java_depset = depset(direct = java_inputs, transitive = [java_runtime[DefaultInfo].files]) + if type(inputs) == "depset": + all_inputs = depset(transitive = [java_depset, inputs]) + else: + all_inputs = depset(direct = inputs, transitive = [java_depset]) + + ctx.actions.run( + executable = str(java_runtime[java_common.JavaRuntimeInfo].java_executable_exec_path), + inputs = all_inputs, + arguments = BASE_JVMOPTS + [java_args] + args, + **kwargs + ) + +def _check_srcs_package(target_package, srcs, attr_name): + """Makes sure the given srcs live in the given package.""" + + # Analogous to RuleContext.checkSrcsSamePackage + for src in srcs: + if target_package != src.owner.package: + fail(("Please do not depend on %s directly in %s. Either move it to this package or " + + "depend on an appropriate rule in its package.") % (src.owner, attr_name)) + +# TODO: Streamline API to generate less actions. +def _kt_jvm_library( + ctx, + kt_toolchain, + srcs = [], + common_srcs = [], + coverage_srcs = [], + manifest = None, # set for Android libs, otherwise None. + merged_manifest = None, # set for Android libs, otherwise None. + resource_files = [], # set for Android libs, otherwise empty. + classpath_resources = [], # set for kt_jvm_library, otherwise empty. + output = None, + output_srcjar = None, # Will derive default filename if not set. + deps = [], + exports = [], # passthrough for JavaInfo constructor + runtime_deps = [], # passthrough for JavaInfo constructor + native_libraries = [], # passthrough of CcInfo for JavaInfo constructor + plugins = _kt_plugins_map(), + pre_processed_java_plugin_processors = sets.make([]), + exported_plugins = [], + android_lint_plugins = [], + android_lint_rules_jars = depset(), # Depset with standalone Android Lint rules Jars + javacopts = [], + kotlincopts = [], + compile_jdeps = depset(), + disable_lint_checks = [], + neverlink = False, + testonly = False, # used by Android Lint + enforce_strict_deps = True, + rule_family = _RULE_FAMILY.UNKNOWN, + enforce_complete_jdeps = False, + java_toolchain = None, + friend_jars = depset(), + annotation_processor_additional_outputs = [], + annotation_processor_additional_inputs = []): + if not java_toolchain: + fail("Missing or invalid java_toolchain") + if not kt_toolchain: + fail("Missing or invalid kt_toolchain") + + merged_deps = java_common.merge(deps) + + # Split sources, as java requires a separate compile step. + kt_srcs = [s for s in srcs if _is_kt_src(s)] + java_srcs = [s for s in srcs if s.path.endswith(_EXT.JAVA)] + java_syncer = _DirSrcjarSyncer(ctx, kt_toolchain, "java") + java_syncer.add_dirs([s for s in srcs if _is_dir(s, "java")]) + java_syncer.add_srcjars([s for s in srcs if s.path.endswith(_EXT.SRCJAR)]) + + expected_srcs = sets.make(kt_srcs + java_srcs + java_syncer.dirs + java_syncer.srcjars) + unexpected_srcs = sets.difference(sets.make(srcs), expected_srcs) + if sets.length(unexpected_srcs) != 0: + fail("Unexpected srcs: %s" % sets.to_list(unexpected_srcs)) + + # Skip srcs package check for android_library targets with no kotlin sources: b/239725424 + if rule_family != _RULE_FAMILY.ANDROID_LIBRARY or kt_srcs: + _check_srcs_package(ctx.label.package, srcs, "srcs") + _check_srcs_package(ctx.label.package, common_srcs, "common_srcs") + _check_srcs_package(ctx.label.package, coverage_srcs, "coverage_srcs") + + # Complete classpath including bootclasspath. Like for Javac, explicitly place direct + # compile_jars before transitive not to confuse strict_deps (b/149107867). + full_classpath = depset( + order = "preorder", + transitive = [ + java_toolchain.bootclasspath, + merged_deps.compile_jars, + merged_deps.transitive_compile_time_jars, + ], + ) + + # Collect all plugin data, including processors to run and all plugin classpaths, + # whether they have processors or not (b/120995492). + # This may include go/errorprone plugin classpaths that kapt will ignore. + java_plugin_datas = [info.plugins for info in plugins.java_plugin_infos] + [dep.plugins for dep in deps] + plugin_processors = [ + cls + for p in java_plugin_datas + for cls in p.processor_classes.to_list() + if not sets.contains(pre_processed_java_plugin_processors, cls) + ] + plugin_classpaths = depset(transitive = [p.processor_jars for p in java_plugin_datas]) + + out_jars = [] + out_srcjars = [] + out_compilejars = [] + kapt_outputs = struct(jar = None, manifest = None, srcjar = None) + + # Kotlin compilation requires two passes when annotation processing is + # required. The initial pass processes the annotations and generates + # additional sources and the following pass compiles the Kotlin code. + # Skip kapt if no plugins have processors (can happen with only + # go/errorprone plugins, # b/110540324) + if kt_srcs and plugin_processors: + kapt_outputs = _kapt( + ctx, + kt_srcs = kt_srcs, + common_srcs = common_srcs, + java_srcs = java_srcs, + plugin_processors = plugin_processors, + plugin_classpaths = plugin_classpaths, + plugin_data = depset(transitive = [p.processor_data for p in java_plugin_datas]), + # Put contents of Bazel flag --javacopt before given javacopts as is Java rules. + # This still ignores package configurations, which aren't exposed to Starlark. + javacopts = (java_common.default_javac_opts(java_toolchain = java_toolchain) + + ctx.fragments.java.default_javac_flags + + javacopts), + kotlincopts = kotlincopts, # don't need strict_deps flags for kapt + toolchain = kt_toolchain, + classpath = full_classpath, + ) + + out_jars.append(kapt_outputs.jar) + java_syncer.add_srcjars([kapt_outputs.srcjar]) + + merged_deps = java_common.merge([merged_deps, JavaInfo( + output_jar = kapt_outputs.jar, + compile_jar = kapt_outputs.jar, + )]) + + kotlinc_result = None + if kt_srcs or common_srcs: + kotlinc_result = _run_kotlinc( + ctx, + kt_srcs = kt_srcs, + common_srcs = common_srcs, + java_srcs_and_dirs = java_srcs + java_syncer.dirs, + output = ctx.actions.declare_file(ctx.label.name + "-kt.jar"), + kotlincopts = kotlincopts, + compile_jdeps = compile_jdeps, + toolchain = kt_toolchain, + classpath = full_classpath, + plugins = plugins, + friend_jars = friend_jars, + enforce_strict_deps = enforce_strict_deps, + enforce_complete_jdeps = enforce_complete_jdeps, + ) + + # Use un-instrumented Jar at compile-time to avoid double-instrumenting inline functions + # (see b/110763361 for the comparable Gradle issue) + out_compilejars.append(kotlinc_result.compile_jar) + out_srcjars.append(kotlinc_result.source_jar) + + # Apply coverage instrumentation if requested, and add dep on JaCoCo runtime to merged_deps. + # The latter helps jdeps computation (b/130747644) but could be runtime-only if we computed + # compile-time Jdeps based using the compile Jar (which doesn't contain instrumentation). + # See b/117897097 for why it's still useful to make the (runtime) dep explicit. + if ctx.coverage_instrumented(): + out_jars.append(_offline_instrument_jar( + ctx, + kt_toolchain, + kotlinc_result.output_jar, + kt_srcs + common_srcs + coverage_srcs, + )) + merged_deps = java_common.merge([merged_deps, kt_toolchain.coverage_runtime]) + else: + out_jars.append(kotlinc_result.output_jar) + + classpath_resources_dirs, classpath_resources_non_dirs = _partition( + classpath_resources, + filter = lambda res: res.is_directory, + ) + if classpath_resources_dirs: + out_jars.append( + _create_jar_from_tree_artifacts( + ctx, + kt_toolchain.jar_tool, + ctx.actions.declare_file(ctx.label.name + "-dir-res.jar"), + classpath_resources_dirs, + ), + ) + + javac_java_info = None + java_native_headers_jar = None + java_gensrcjar = None + java_genjar = None + if java_srcs or java_syncer.srcjars or classpath_resources: + javac_out = ctx.actions.declare_file(ctx.label.name + "-java.jar") + javac_java_info = java_common.compile( + ctx, + source_files = java_srcs, + source_jars = java_syncer.srcjars, + resources = classpath_resources_non_dirs, + output = javac_out, + deps = ([JavaInfo(**structs.to_dict(kotlinc_result))] if kotlinc_result else []) + [merged_deps], + # Include default_javac_flags, which reflect Blaze's --javacopt flag, so they win over + # all sources of default flags (for Ellipsis builds, see b/125452475). + # TODO: remove default_javac_flags here once java_common.compile is fixed. + javac_opts = ctx.fragments.java.default_javac_flags + javacopts, + plugins = plugins.java_plugin_infos, + strict_deps = "DEFAULT", + java_toolchain = java_toolchain, + neverlink = neverlink, + # Enable annotation processing for java-only sources to enable data binding + enable_annotation_processing = not kt_srcs, + annotation_processor_additional_outputs = annotation_processor_additional_outputs, + annotation_processor_additional_inputs = annotation_processor_additional_inputs, + ) + out_jars.append(javac_out) + out_srcjars.extend(javac_java_info.source_jars) + out_compilejars.extend(javac_java_info.compile_jars.to_list()) # unpack singleton depset + java_native_headers_jar = javac_java_info.outputs.native_headers + + if kt_srcs: + java_gensrcjar = kapt_outputs.srcjar + java_genjar = _derive_gen_class_jar(ctx, kt_toolchain, kapt_outputs.manifest, javac_out, java_srcs) + else: + java_gensrcjar = javac_java_info.annotation_processing.source_jar + java_genjar = javac_java_info.annotation_processing.class_jar + if java_gensrcjar: + java_syncer.add_srcjars([java_gensrcjar]) + + jdeps_output = None + compile_jdeps_output = None + manifest_proto = None + + # TODO: Move severity overrides to config file when possible again + blocking_action_outs = [] + + if output_srcjar == None: + output_srcjar = ctx.actions.declare_file("lib%s-src.jar" % ctx.label.name) + compile_jar = ctx.actions.declare_file(ctx.label.name + "-compile.jar") + single_jar = java_toolchain.single_jar + _singlejar(ctx, out_srcjars, output_srcjar, single_jar, mnemonic = "KtMergeSrcjar", content = "srcjar", preserve_compression = True) + + # Don't block compile-time Jar on Android Lint and other validations (b/117991324). + _singlejar(ctx, out_compilejars, compile_jar, single_jar, mnemonic = "KtMergeCompileJar", content = "compile-time Jar") + + # Disable validation for Guitar BUILD targets (b/144326858). + # TODO Remove use of RUN_ANALYSIS_TIME_VALIDATION once Guitar disables validations + use_validation = ctx.var.get("RUN_ANALYSIS_TIME_VALIDATION", "true") # will be "0" if set by Guitar + use_validation = ctx.var.get("kt_use_validations", use_validation) + + # Include marker file in runtime Jar so we can reliably identify 1P Kotlin code + # TODO: consider only doing this for kt_android_library + _singlejar( + ctx, + out_jars + ([kt_toolchain.build_marker] if kt_srcs and ctx.label.package.startswith("java/") else []), + output, + single_jar, + preserve_compression = True, + pseudo_inputs = ([] if use_validation == "true" else blocking_action_outs), + ) + result_java_info = JavaInfo( + output_jar = output, + compile_jar = compile_jar, + source_jar = output_srcjar, + deps = deps, + exports = exports, + exported_plugins = exported_plugins, + runtime_deps = runtime_deps, + manifest_proto = manifest_proto, + neverlink = neverlink, + jdeps = jdeps_output, + compile_jdeps = compile_jdeps_output, + native_libraries = native_libraries, + native_headers_jar = java_native_headers_jar, + generated_source_jar = java_gensrcjar, + generated_class_jar = java_genjar, + ) + + return struct( + java_info = result_java_info, + validations = (blocking_action_outs if use_validation == "true" else []), + ) + +def _kt_jvm_import( + ctx, + jars = [], + srcjar = None, + deps = [], + runtime_deps = [], + neverlink = False, + java_toolchain = None, + deps_checker = None): + if not java_toolchain: + fail("Missing or invalid java_toolchain") + merged_deps = java_common.merge(deps) + + # Check that any needed deps are declared unless neverlink, in which case Jars won't be used + # at runtime so we skip the check, though we'll populate jdeps either way. + jdeps_output = ctx.actions.declare_file(ctx.label.name + ".jdeps") + _check_deps( + ctx, + jars_to_check = jars, + merged_deps = merged_deps, + enforce_strict_deps = not neverlink, + jdeps_output = jdeps_output, + deps_checker = deps_checker, + java_toolchain = java_toolchain, + ) + + if not jars: + fail("Must provide a Jar to use kt_jvm_import") + + java_info = java_common.merge([ + JavaInfo( + output_jar = jar, + compile_jar = jar, + source_jar = srcjar, + deps = deps, + runtime_deps = runtime_deps, + neverlink = neverlink, + # TODO: Set compile-time jdeps to help reduce Javac classpaths downstream + jdeps = jdeps_output, # not clear this is useful but let's populate since we have it + ) + for jar in jars + ]) + + # TODO Remove use of RUN_ANALYSIS_TIME_VALIDATION once Guitar disables validations + use_validation = ctx.var.get("RUN_ANALYSIS_TIME_VALIDATION", "true") # will be "0" if set by Guitar + + return struct( + java_info = java_info, + validations = [jdeps_output] if use_validation == "true" and not neverlink else [], + ) + +def _validate_proguard_specs( + ctx, + proguard_specs, + proguard_allowlister): + validated_proguard_specs = [] + for proguard_spec in proguard_specs: + validated_proguard_spec = ctx.actions.declare_file( + "validated_proguard/%s/%s_valid" % (ctx.label.name, proguard_spec.path), + ) + validated_proguard_specs.append(validated_proguard_spec) + + args = ctx.actions.args() + args.add("--path", proguard_spec) + args.add("--output", validated_proguard_spec) + + ctx.actions.run( + executable = proguard_allowlister, + arguments = [args], + inputs = [proguard_spec], + outputs = [validated_proguard_spec], + mnemonic = "ValidateProguard", + progress_message = ( + "Validating proguard configuration %s" % proguard_spec + ), + ) + return validated_proguard_specs + +def _collect_proguard_specs( + ctx, + proguard_specs, + propagated_deps, + proguard_allowlister): + validated_proguard_specs = _validate_proguard_specs( + ctx, + proguard_specs, + proguard_allowlister, + ) + + return depset( + validated_proguard_specs, + transitive = [p.specs for p in _collect_providers(ProguardSpecProvider, propagated_deps)], + order = "preorder", + ) + +def _collect_providers(provider, deps): + """Collects the requested provider from the given list of deps.""" + return [dep[provider] for dep in deps if provider in dep] + +def _partition(sequence, filter): + pos, neg = [], [] + for element in sequence: + if filter(element): + pos.append(element) + else: + neg.append(element) + return pos, neg + +common = struct( + ALLOWED_ANDROID_RULES = _ALLOWED_ANDROID_RULES, + ALLOWED_JVM_RULES = _ALLOWED_JVM_RULES, + JAR_FILE_TYPE = _JAR_FILE_TYPE, + JVM_FLAGS = BASE_JVMOPTS, + KT_FILE_TYPES = _KT_FILE_TYPES, + KT_JVM_FILE_TYPES = _KT_JVM_FILE_TYPES, + RULE_FAMILY = _RULE_FAMILY, + SRCJAR_FILE_TYPES = _SRCJAR_FILE_TYPES, + collect_proguard_specs = _collect_proguard_specs, + collect_providers = _collect_providers, + create_jar_from_tree_artifacts = _create_jar_from_tree_artifacts, + is_kt_src = _is_kt_src, + kt_jvm_import = _kt_jvm_import, + kt_jvm_library = _kt_jvm_library, + kt_plugins_map = _kt_plugins_map, + partition = _partition, +) diff --git a/kotlin/compiler_opt.bzl b/kotlin/compiler_opt.bzl new file mode 100644 index 0000000..e7a89d5 --- /dev/null +++ b/kotlin/compiler_opt.bzl @@ -0,0 +1,83 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""A rule for declaring and passing kotlinc opts in a restricted way. + +It is a goal for rules_kotlin that Kotlin libraries use consistent default compiler +options across as much of the repo as possible. Doing so makes Kotlin easier to +maintain at scale. + +If an exception needs to be made for some library, `kt_compiler_opt` can be used to +declare a set of additional options with restricted visibility. That target can then +be passed to the `custom_kotlincopts` attribute. The set of directories that allow +`kt_compiler_opt` targets is also limited, to prevent misuse. +""" + +# Intentionally private to prevent misuse. +_KtCompilerOptInfo = provider( + doc = "A restricted set of kotlinc opts", + fields = {"opts": "list[string]"}, +) + +_ALLOWED_ROOTS = [ +] + +_ALLOWED_VISIBILITY_NAMES = [ + "__pkg__", + "__subpackages__", +] + +def _kt_compiler_opt_impl(ctx): + if not any([ctx.label.package.startswith(p) for p in _ALLOWED_ROOTS]): + fail("kt_compiler_opt is only allowed under " + str(_ALLOWED_ROOTS)) + + visibility_groups = [v for v in ctx.attr.visibility if not v.name in _ALLOWED_VISIBILITY_NAMES] + if len(visibility_groups) > 0: + fail("Using package groups for visibility may expose custom options too broadly: " + str(visibility_groups)) + + return [_KtCompilerOptInfo(opts = ctx.attr.opts)] + +kt_compiler_opt = rule( + implementation = _kt_compiler_opt_impl, + attrs = { + "opts": attr.string_list( + doc = "The opt(s) this target represents.", + mandatory = True, + ), + }, +) + +def kotlincopts_attrs(): + return dict( + custom_kotlincopts = attr.label_list( + doc = "kt_compiler_opt targets to pass to Kotlin compiler. Most users should not need this attr.", + providers = [[_KtCompilerOptInfo]], + cfg = "exec", + ), + ) + +def merge_kotlincopts(ctx): + """Returns the complete list of opts behind custom_kotlincopts + + Args: + ctx: A ctx matching kotlincopts_attrs + + Returns: + The list of opts + """ + custom_opts = [] + for target in ctx.attr.custom_kotlincopts: + custom_opts.extend(target[_KtCompilerOptInfo].opts) + + return custom_opts diff --git a/kotlin/compiler_plugin.bzl b/kotlin/compiler_plugin.bzl new file mode 100644 index 0000000..3527aee --- /dev/null +++ b/kotlin/compiler_plugin.bzl @@ -0,0 +1,82 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""A rule for declaring and passing kotlinc plugins.""" + +_KtCompilerPluginInfo = provider( + doc = "Info for running a plugin that directly registers itself to kotlinc extension points", + fields = dict( + plugin_id = "string", + jar = "File", + args = "list[string]", + ), +) + +KtCompilerPluginInfo, _make_kt_compiler_plugin_info = (_KtCompilerPluginInfo, _KtCompilerPluginInfo) + +def _kt_compiler_plugin_impl(ctx): + + return [ + JavaPluginInfo( + runtime_deps = [], + processor_class = None, + ), + _make_kt_compiler_plugin_info( + plugin_id = ctx.attr.plugin_id, + jar = ctx.file.jar or ctx.attr.jar[JavaInfo].output_jar, + args = [ + "plugin:%s:%s=%s" % (ctx.attr.plugin_id, k, v) + for (k, v) in ctx.attr.args.items() + ], + ), + ] + +kt_compiler_plugin = rule( + implementation = _kt_compiler_plugin_impl, + attrs = dict( + plugin_id = attr.string( + doc = "ID used to register this plugin with kotlinc", + mandatory = True, + ), + jar = attr.label( + doc = "JAR that provides the plugin implementation", + mandatory = True, + allow_single_file = [".jar"], + cfg = "exec", + ), + args = attr.string_dict( + doc = """Args to pass to the plugin + + The rule impl will format key-value pairs for the koltinc + CLI. All plugin invocations will receive the same args. + """, + default = {}, + ), + ), + provides = [ + JavaPluginInfo, # Allow this rule to be passed to java rules + KtCompilerPluginInfo, + ], +) + +def _get_exported_plugins(_target, ctx_rule): + return [t[KtCompilerPluginInfo] for t in getattr(ctx_rule.attr, "exported_plugins", []) if (KtCompilerPluginInfo in t)] + +kt_compiler_plugin_visitor = struct( + name = "compiler_plugins", + visit_target = _get_exported_plugins, + filter_edge = None, + finish_expansion = None, + process_unvisited_target = None, +) diff --git a/kotlin/compiler_plugin_export.bzl b/kotlin/compiler_plugin_export.bzl new file mode 100644 index 0000000..d0ff426 --- /dev/null +++ b/kotlin/compiler_plugin_export.bzl @@ -0,0 +1,62 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Convenience macro for getting `kt_compiler_plugin` into uncooperative rules. + +Some targets (Z), where we would like to export a plugin (Y), use rules that don't +support `exported_plugins` (e.g android_library). To solve this, we create a dummy +target (X) that has `X.exported_plugins = [Y]`, and then set `Z.exports = [Y]`. +This creates a chain of exports for `kt_traverse_exports` to follow when discovering +`kt_compiler_plugin`s. +""" + +load(":compiler_plugin.bzl", "kt_compiler_plugin") +load(":jvm_import.bzl", "kt_jvm_import") + +def _kt_compiler_plugin_export( + name, + visibility = [], + compatible_with = [], + **kwargs): + if not name.endswith("_plugin_export"): + fail() + + basename = name.replace("_plugin_export", "") + + kt_jvm_import( + name = name, + exported_plugins = [basename + "_plugin"], + jars = [basename + "_empty_jar"], + compatible_with = compatible_with, + visibility = visibility, + neverlink = True, # Don't link kotlin stdlib into Java users + ) + + kt_compiler_plugin( + name = basename + "_plugin", + visibility = visibility, + compatible_with = compatible_with, + **kwargs + ) + + native.genrule( + name = basename + "_empty_jar", + visibility = visibility, + outs = [name + "_empty.jar"], + cmd = """$(location @bazel_tools//tools/zip:zipper) c $@ "assets/_empty=" """, + compatible_with = compatible_with, + tools = ["@bazel_tools//tools/zip:zipper"], + ) + +kt_compiler_plugin_export = _kt_compiler_plugin_export diff --git a/kotlin/direct_jdeps.bzl b/kotlin/direct_jdeps.bzl new file mode 100644 index 0000000..f242989 --- /dev/null +++ b/kotlin/direct_jdeps.bzl @@ -0,0 +1,26 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""kt_traverse_exports visitor for exposing jdeps files from direct deps.""" + +def _get_jdeps(target, _ctx_rule): + return [out.compile_jdeps for out in target[JavaInfo].java_outputs if out.compile_jdeps] + +kt_direct_jdeps_visitor = struct( + name = "direct_jdeps", + visit_target = _get_jdeps, + filter_edge = None, + process_unvisited_target = None, + finish_expansion = None, +) diff --git a/kotlin/forbidden_deps.bzl b/kotlin/forbidden_deps.bzl new file mode 100644 index 0000000..67a04fb --- /dev/null +++ b/kotlin/forbidden_deps.bzl @@ -0,0 +1,65 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""kt_traverse_exports visitor for identifying forbidden deps of Kotlin rules. + +Currently this system recognizes: + - nano protos + - targets in forbidden packages + - targets exporting other forbidden targets +""" + +load("@bazel_skylib//lib:sets.bzl", "sets") +load("//bazel:stubs.bzl", "EXEMPT_DEPS", "FORBIDDEN_DEP_PACKAGES") + +def _error(target, msg): + return (str(target.label), msg) + +def _is_exempt(target): + return sets.contains(EXEMPT_DEPS, str(target.label)) + +def _check_forbidden(target, ctx_rule): + if _is_exempt(target): + return [] + + if sets.contains(FORBIDDEN_DEP_PACKAGES, target.label.package): + return [_error(target, "Forbidden package")] + + # Identify nano protos using tag (b/122083175) + for tag in ctx_rule.attr.tags: + if "nano_proto_library" == tag: + return [_error(target, "nano_proto_library")] + + return [] + +def _if_not_checked(target): + return [] if _is_exempt(target) else [_error(target, "Not checked")] + +def _validate_deps(error_set): + if not error_set: + return + + error_lines = [ + " " + name + " : " + msg + for (name, msg) in error_set.to_list() + ] + fail("Forbidden deps, see go/kotlin/build-rules#restrictions:\n" + "\n".join(error_lines)) + +kt_forbidden_deps_visitor = struct( + name = "forbidden_deps", + visit_target = _check_forbidden, + filter_edge = None, + process_unvisited_target = _if_not_checked, + finish_expansion = _validate_deps, +) diff --git a/kotlin/friend_jars.bzl b/kotlin/friend_jars.bzl new file mode 100644 index 0000000..4efb435 --- /dev/null +++ b/kotlin/friend_jars.bzl @@ -0,0 +1,66 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""TODO: Write module docstring.""" + +def _is_eligible_friend(target, friend): + """ + Determines if `target` is allowed to call `friend` a friend (and use its `internal` members). + + To be eligible, `target` must be one of: + - in the parallel `java/` package from a `javatests/` package + - in the parallel `main/java` package from a `test/java` package + - another target in the same `BUILD` file + + Args: + target: (target) The current target + friend: (Target) A potential friend of `target` + """ + + target_pkg = target.label.package + "/" + friend_pkg = friend.label.package + "/" + + if target_pkg == friend_pkg: + # Allow friends on targets in the same package + return True + + if "javatests/" in target_pkg and "java/" in friend_pkg: + # Allow friends from javatests/ on the parallel java/ package + target_java_pkg = target_pkg.rsplit("javatests/", 1)[1] + friend_java_pkg = friend_pkg.rsplit("java/", 1)[1] + if target_java_pkg == friend_java_pkg: + return True + + if ("test/java/" in target_pkg and "main/java/" in friend_pkg and + True): + # Allow friends from test/java on the parallel main/java package + target_split = target_pkg.rsplit("test/java/", 1) + friend_split = friend_pkg.rsplit("main/java/", 1) + if target_split == friend_split: + return True + + return False + +def _get_output_jars(target, _ctx_rule): + # We can't simply use `JavaInfo.compile_jars` because we only want the JARs directly created by + # `target`, and not JARs from its `exports` + return [output.compile_jar for output in target[JavaInfo].java_outputs if output.compile_jar] + +kt_friend_jars_visitor = struct( + name = "friend_jars", + visit_target = _get_output_jars, + filter_edge = _is_eligible_friend, + finish_expansion = None, + process_unvisited_target = None, +) diff --git a/kotlin/java_plugin.internal.bzl b/kotlin/java_plugin.internal.bzl new file mode 100644 index 0000000..08f5463 --- /dev/null +++ b/kotlin/java_plugin.internal.bzl @@ -0,0 +1,36 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Utilities related to java_plugin and JavaPluginInfo. + +kt_codegen_plugin is using this visitor to extract java_plugin information. +Due to cross plugin type processing, the plugin info search processor differs +from the way that java targets handles plugins. +""" + +def _get_java_plugins(_target, ctx_rule): + exported_plugins = getattr(ctx_rule.attr, "exported_plugins", []) + return [ + t[JavaPluginInfo] + for t in exported_plugins + if JavaPluginInfo in t + ] + +java_plugin_visitor = struct( + name = "java_plugins", + visit_target = _get_java_plugins, + filter_edge = None, + finish_expansion = None, + process_unvisited_target = None, +) diff --git a/kotlin/jvm_compile.bzl b/kotlin/jvm_compile.bzl new file mode 100644 index 0000000..694a8a4 --- /dev/null +++ b/kotlin/jvm_compile.bzl @@ -0,0 +1,207 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Compile method that can compile kotlin or java sources""" + +load(":common.bzl", "common") +load(":traverse_exports.bzl", "kt_traverse_exports") +load(":compiler_plugin.bzl", "KtCompilerPluginInfo") +load("@bazel_skylib//lib:sets.bzl", "sets") + +_RULE_FAMILY = common.RULE_FAMILY + +def kt_jvm_compile( + ctx, + output, + srcs, + common_srcs, + deps, + plugins, + runtime_deps, + exports, + javacopts, + kotlincopts, + neverlink, + testonly, + android_lint_plugins, + resource_files, + exported_plugins, + manifest = None, + merged_manifest = None, + classpath_resources = [], + kt_toolchain = None, + java_toolchain = None, + android_lint_rules_jars = depset(), + disable_lint_checks = [], + r_java = None, + output_srcjar = None, + flogger_runtime = None, + rule_family = _RULE_FAMILY.UNKNOWN, + annotation_processor_additional_outputs = [], + annotation_processor_additional_inputs = [], + coverage_srcs = [], + **_kwargs): + """ + The Kotlin JVM Compile method. + + Args: + ctx: The context. + output: A File. The output jar. + srcs: List of Files. The Kotlin and Java sources. + common_srcs: List of common source files. + deps: List of targets. A list of dependencies. + plugins: List of targets. A list of jvm plugins. + runtime_deps: List of targets. A list of runtime deps. + exports: List of targets. A list of exports. + javacopts: List of strings. A list of Java compile options. + kotlincopts: List of strings. A list of Kotlin compile options. + neverlink: A bool. Signifies whether the target is only used for compile-time. + testonly: A bool. Signifies whether the target is only used for testing only. + android_lint_plugins: List of targets. An list of android lint plugins to + execute as a part of linting. + resource_files: List of Files. The list of Android Resource files. + exported_plugins: List of exported javac/kotlinc plugins + manifest: A File. The raw Android manifest. Optional. + merged_manifest: A File. The merged Android manifest. Optional. + classpath_resources: List of Files. The list of classpath resources (kt_jvm_library only). + kt_toolchain: The Kotlin toolchain. + java_toolchain: The Java toolchain. + android_lint_rules_jars: Depset of Files. Standalone Android Lint rule Jar artifacts. + disable_lint_checks: Whether to disable link checks. + NOTE: This field should only be used when the provider is not produced + by a target. For example, the JavaInfo created for the Android R.java + within an android_library rule. + r_java: A JavaInfo provider. The JavaInfo provider for the Android R.java + which is both depended on and propagated as an export. + NOTE: This field accepts a JavaInfo, but should only be used for the + Android R.java within an android_library rule. + output_srcjar: Target output file for generated source jar. Default filename used if None. + flogger_runtime: JavaInfo, Flogger runtime. Optional + rule_family: The family of the rule calling this function. Element of common.RULE_FAMILY. + May be used to enable/disable some features. + annotation_processor_additional_outputs: sequence of Files. A list of + files produced by an annotation processor. + annotation_processor_additional_inputs: sequence of Files. A list of + files consumed by an annotation processor. + coverage_srcs: Files to use as the basis when computing code coverage. These are typically + handwritten files that were inputs to generated `srcs`. Should be disjoint with `srcs`. + **_kwargs: Unused kwargs so that parameters are easy to add and remove. + + Returns: + A struct that carries the following fields: java_info and validations. + """ + if rule_family != _RULE_FAMILY.ANDROID_LIBRARY and not (srcs + common_srcs + exports): + # Demands either of the following to be present. + # - Source-type artifacts, srcs or common_srcs, including an empty + # tree-artifact (a directory) or a srcjar without jar entries. + # - Exporting targets, exports. It is typically used by a library author + # to publish one user-facing target with direct exposure to its + # dependent libraries. + fail("Expected one of (srcs, common_srcs, exports) is not empty for kotlin/jvm_compile on target: {}".format(ctx.label)) + + if type(java_toolchain) != "JavaToolchainInfo": + # Allow passing either a target or a provider until all callers are updated + java_toolchain = java_toolchain[java_common.JavaToolchainInfo] + + srcs = list(srcs) + classpath_resources = list(classpath_resources) + java_infos = [] + pre_processed_java_plugin_processors = sets.make([]) + use_flogger = False + + # Skip deps validation check for any android_library target with no kotlin sources: b/239721906 + has_kt_srcs = any([common.is_kt_src(src) for src in srcs]) + if rule_family != _RULE_FAMILY.ANDROID_LIBRARY or has_kt_srcs: + kt_traverse_exports.expand_forbidden_deps(deps + runtime_deps + exports) + + for dep in deps: + # Collect JavaInfo providers and info about plugins (JavaPluginData). + if JavaInfo in dep: + java_infos.append(dep[JavaInfo]) + + else: + fail("Unexpected dependency (must provide JavaInfo): %s" % dep.label) + + if rule_family != _RULE_FAMILY.ANDROID_LIBRARY or srcs or common_srcs: + java_infos.extend(kt_toolchain.kotlin_libs) + + # TODO: Inject the runtime library from the flogger API target + if use_flogger: + if not flogger_runtime: + fail("Dependency on flogger exists, but flogger_runtime not passed") + java_infos.append(flogger_runtime) + + if kotlincopts != None and "-Werror" in kotlincopts: + fail("Flag -Werror is not permitted") + + if classpath_resources and rule_family != _RULE_FAMILY.JVM_LIBRARY: + fail("resources attribute only allowed for jvm libraries") + + # The r_java field only support Android resources Jar files. For now, verify + # that the name of the jar matches "_resources.jar". This check does not to + # prevent malicious use, the intent is to prevent accidental usage. + r_java_info = [] + if r_java: + for jar in r_java.outputs.jars: + if not jar.class_jar.path.endswith("_resources.jar"): + fail("Error, illegal dependency provided for r_java. This " + + "only supports Android resource Jar files, " + + "'*_resources.jar'.") + r_java_info.append(r_java) + + return common.kt_jvm_library( + ctx, + android_lint_plugins = android_lint_plugins, # List of JavaInfo + android_lint_rules_jars = android_lint_rules_jars, + classpath_resources = classpath_resources, + common_srcs = common_srcs, + coverage_srcs = coverage_srcs, + deps = r_java_info + java_infos, + disable_lint_checks = disable_lint_checks, + exported_plugins = [e[JavaPluginInfo] for e in exported_plugins if (JavaPluginInfo in e)], + # Not all exported targets contain a JavaInfo (e.g. some only have CcInfo) + exports = r_java_info + [e[JavaInfo] for e in exports if JavaInfo in e], + friend_jars = kt_traverse_exports.expand_friend_jars(deps, root = ctx), + java_toolchain = java_toolchain, + javacopts = javacopts, + kotlincopts = kotlincopts, + compile_jdeps = kt_traverse_exports.expand_direct_jdeps(deps), + kt_toolchain = kt_toolchain, + manifest = manifest, + merged_manifest = merged_manifest, + native_libraries = [p[CcInfo] for p in deps + runtime_deps + exports if CcInfo in p], + neverlink = neverlink, + output = output, + output_srcjar = output_srcjar, + plugins = common.kt_plugins_map( + java_plugin_infos = [plugin[JavaPluginInfo] for plugin in plugins if (JavaPluginInfo in plugin)], + kt_compiler_plugin_infos = + kt_traverse_exports.expand_compiler_plugins(deps).to_list() + [ + plugin[KtCompilerPluginInfo] + for plugin in plugins + if (KtCompilerPluginInfo in plugin) + ], + ), + pre_processed_java_plugin_processors = pre_processed_java_plugin_processors, + resource_files = resource_files, + runtime_deps = [d[JavaInfo] for d in runtime_deps if JavaInfo in d], + srcs = srcs, + testonly = testonly, + rule_family = rule_family, + annotation_processor_additional_outputs = annotation_processor_additional_outputs, + annotation_processor_additional_inputs = annotation_processor_additional_inputs, + ) + +# TODO Delete this +compile = kt_jvm_compile diff --git a/kotlin/jvm_import.bzl b/kotlin/jvm_import.bzl new file mode 100644 index 0000000..ed740ca --- /dev/null +++ b/kotlin/jvm_import.bzl @@ -0,0 +1,164 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Kotlin kt_jvm_import rule.""" + +load(":common.bzl", "common") +load(":traverse_exports.bzl", "kt_traverse_exports") +load("//toolchains/kotlin_jvm:kt_jvm_toolchains.bzl", "kt_jvm_toolchains") +load("//toolchains/kotlin_jvm:java_toolchains.bzl", "java_toolchains") +load("@bazel_skylib//lib:dicts.bzl", "dicts") +load(":compiler_plugin.bzl", "KtCompilerPluginInfo") + +def _kt_jvm_import_impl(ctx): + kt_jvm_toolchain = kt_jvm_toolchains.get(ctx) + + if not ctx.files.jars: + fail("List of jars cannot be empty") + + deps_java_infos = [] + for dep in ctx.attr.deps: + deps_java_infos.append(dep[JavaInfo]) + + # Put Kotlin's standard libs last to match what kotlinc would do without -no-stdlib + deps_java_infos.extend(kt_jvm_toolchain.kotlin_libs) + + runtime_deps_java_infos = [] + for runtime_dep in ctx.attr.runtime_deps: + # Collect JavaInfo providers + if JavaInfo in runtime_dep: + runtime_deps_java_infos.append(runtime_dep[JavaInfo]) + elif CcInfo not in runtime_dep: + fail("Unexpected runtime dependency (must provide JavaInfo or CcInfo): %" % runtime_dep.label) + + result = common.kt_jvm_import( + ctx, + jars = ctx.files.jars, + srcjar = ctx.file.srcjar, + deps = deps_java_infos, + runtime_deps = runtime_deps_java_infos, + neverlink = ctx.attr.neverlink, + java_toolchain = java_toolchains.get(ctx), + deps_checker = ctx.executable._deps_checker, + ) + result_java_info = result.java_info + + # Collect runfiles from deps unless neverlink + runfiles = None + if not ctx.attr.neverlink: + transitive_runfiles = [] + for p in common.collect_providers(DefaultInfo, ctx.attr.deps): + transitive_runfiles.append(p.data_runfiles.files) + transitive_runfiles.append(p.default_runfiles.files) + runfiles = ctx.runfiles( + files = ctx.files.jars, + transitive_files = depset(transitive = transitive_runfiles), + collect_default = True, # handles data attribute + ) + + return [ + result_java_info, + ProguardSpecProvider(common.collect_proguard_specs( + ctx, + ctx.files.proguard_specs, + ctx.attr.deps, + kt_jvm_toolchain.proguard_whitelister, + )), + OutputGroupInfo(_validation = depset(result.validations)), + DefaultInfo(runfiles = runfiles), # rule doesn't build any files + ] + +_KT_JVM_IMPORT_ATTRS = dicts.add( + java_toolchains.attrs, + kt_jvm_toolchains.attrs, + deps = attr.label_list( + # We allow android rule deps to make importing android JARs easier. + allow_rules = common.ALLOWED_JVM_RULES + common.ALLOWED_ANDROID_RULES, + aspects = [kt_traverse_exports.aspect], + providers = [ + # Each provider-set expands on allow_rules + [JavaInfo], + ], + doc = """The list of libraries this library directly depends on at compile-time. For Java + and Kotlin libraries listed, the Jars they build as well as the transitive closure + of their `deps` and `exports` will be on the compile-time classpath for this rule; + also, the transitive closure of their `deps`, `runtime_deps`, and `exports` will be + on the runtime classpath (excluding dependencies only depended on as `neverlink`). + + Note on strict_deps: any Java type explicitly or implicitly referred to in `srcs` + must be included here. This is a stronger requirement than what is enforced for + `java_library`. Any build failures resulting from this requirement will include the + missing dependencies and a command to fix the rule.""", + ), + exported_plugins = attr.label_list( + providers = [[KtCompilerPluginInfo]], + cfg = "exec", + doc = """JVM plugins to export to users. + + + Every plugin listed will run during compliations that depend on this target, as + if it were listed directly in that target's `plugins` attribute. `java_*` targets + will not run kotlinc plugins""", + ), + jars = attr.label_list( + allow_files = common.JAR_FILE_TYPE, + allow_empty = False, + doc = """The list of Java and/or Kotlin JAR files provided to targets that depend on this + target (required). Currently only a single Jar is supported.""", + ), + neverlink = attr.bool( + default = False, + doc = """Only use this library for compilation and not at runtime.""", + ), + proguard_specs = attr.label_list( + allow_files = True, + doc = """Proguard specifications to go along with this library.""", + ), + runtime_deps = attr.label_list( + # TODO: Delete common.ALLOWED_ANDROID_RULES + allow_rules = common.ALLOWED_JVM_RULES + common.ALLOWED_ANDROID_RULES, + providers = [ + # Each provider-set expands on allow_rules + [CcInfo], # for JNI / native dependencies + ], + aspects = [kt_traverse_exports.aspect], + doc = """Runtime-only dependencies.""", + ), + srcjar = attr.label( + allow_single_file = common.SRCJAR_FILE_TYPES, + doc = """A JAR file that contains source code for the compiled JAR files.""", + ), + _deps_checker = attr.label( + default = "@bazel_tools//tools/android:aar_import_deps_checker", + executable = True, + cfg = "exec", + ), +) + +kt_jvm_import = rule( + attrs = _KT_JVM_IMPORT_ATTRS, + fragments = ["java"], + provides = [JavaInfo], + implementation = _kt_jvm_import_impl, + toolchains = [kt_jvm_toolchains.type], + doc = """Allows the use of precompiled Kotlin `.jar` files as deps of `kt_*` targets. + + Prefer this rule to `java_import` for Kotlin Jars. Most Java-like libraries + and binaries can depend on this rule, and this rule can in turn depend on Kotlin and + Java libraries. This rule supports a subset of attributes supported by `java_import`. + + In addition to documentation provided as part of this rule, please also refer to their + documentation as part of `java_import`. + """, +) diff --git a/kotlin/jvm_library.bzl b/kotlin/jvm_library.bzl new file mode 100644 index 0000000..f2ffe09 --- /dev/null +++ b/kotlin/jvm_library.bzl @@ -0,0 +1,126 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Kotlin kt_jvm_library rule.""" + +load(":jvm_library.internal.bzl", "kt_jvm_library_helper") +load("//bazel:stubs.bzl", "register_extension_info") + +def kt_jvm_library( + name, + srcs = None, + common_srcs = None, + data = None, + exports = None, + deps = None, + runtime_deps = None, + proguard_specs = None, + plugins = None, + exported_plugins = None, + resources = None, + tags = None, + testonly = None, # None to preserve Blaze's defaults, b/112708042 + javacopts = None, + custom_kotlincopts = None, + disable_lint_checks = None, + compatible_with = None, + restricted_to = None, + transitive_configs = None, + visibility = None, + deprecation = None, + features = []): + """This rule compiles Kotlin (and Java) sources into a Jar file. + + Most Java-like libraries + and binaries can depend on this rule, and this rule can in turn depend on Kotlin and + Java libraries. This rule supports a subset of attributes supported by `java_library`. + In addition to documentation provided as part of this rule, please also refer to their + documentation as part of `java_library`. + + Args: + name: Name of the target. + srcs: A list of sources to compile. + common_srcs: A list of common sources to compile for multi-platform projects. + data: A list of data dependencies. + exports: A list of targets to export to rules that depend on this one. + deps: A list of dependencies. NOTE: kt_library targets cannot be added here (yet). + runtime_deps: Libraries to make available to the final binary or test at runtime only. + proguard_specs: Proguard specifications to go along with this library. + plugins: Java annotation processors to run at compile-time. + exported_plugins: https://bazel.build/reference/be/java#java_plugin rules to export to direct + dependencies. + resources: A list of data files to include in the Jar, see + https://bazel.build/reference/be/java#java_library.resources. + tags: A list of string tags passed to generated targets. + testonly: Whether this target is intended only for tests. + javacopts: Additional flags to pass to javac if used. + custom_kotlincopts: Additional flags to pass to Kotlin compiler. + disable_lint_checks: A list of AndroidLint checks to be skipped. + compatible_with: Standard attribute, see + https://bazel.build/reference/be/common-definitions#common.compatible_with. + restricted_to: Standard attribute, see + https://bazel.build/reference/be/common-definitions#common.restricted_to. + transitive_configs: Blaze feature flags (if any) on which this target depends. + visibility: A list of targets allowed to depend on this rule. + deprecation: Standard attribute, see + https://bazel.build/reference/be/common-definitions#common.deprecation. + features: Features enabled. + """ + srcs = srcs or [] + common_srcs = common_srcs or [] + data = data or [] + exports = exports or [] + deps = deps or [] + runtime_deps = runtime_deps or [] + plugins = plugins or [] + exported_plugins = exported_plugins or [] + proguard_specs = proguard_specs or [] + resources = resources or [] + + # Helps go/build_cleaner to identify the targets generated by the macro. + tags = (tags or []) + ["kt_jvm_library"] + + # Ask go/build_cleaner to avoid all generated targets. + javacopts = javacopts or [] + disable_lint_checks = disable_lint_checks or [] + + kt_jvm_library_helper( + name = name, + srcs = srcs, + common_srcs = common_srcs, + deps = deps, + exports = exports, + runtime_deps = runtime_deps, + plugins = plugins, + exported_plugins = exported_plugins, + resources = resources, + javacopts = javacopts, + custom_kotlincopts = custom_kotlincopts, + proguard_specs = proguard_specs, + data = data, + disable_lint_checks = disable_lint_checks, + tags = tags, + testonly = testonly, + compatible_with = compatible_with, + restricted_to = restricted_to, + transitive_configs = transitive_configs, + visibility = visibility, + deprecation = deprecation, + features = features, + ) + +register_extension_info( + extension = kt_jvm_library, + label_regex_for_dep = "{extension_name}", +) diff --git a/kotlin/jvm_library.internal.bzl b/kotlin/jvm_library.internal.bzl new file mode 100644 index 0000000..7334f95 --- /dev/null +++ b/kotlin/jvm_library.internal.bzl @@ -0,0 +1,253 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Kotlin kt_jvm_library rule.""" + +load("//kotlin:compiler_opt.bzl", "kotlincopts_attrs", "merge_kotlincopts") +load("//toolchains/kotlin_jvm:java_toolchains.bzl", "java_toolchains") +load("//toolchains/kotlin_jvm:kt_jvm_toolchains.bzl", "kt_jvm_toolchains") +load("@bazel_skylib//lib:dicts.bzl", "dicts") +load(":common.bzl", "common") +load(":compiler_plugin.bzl", "KtCompilerPluginInfo") +load(":traverse_exports.bzl", "kt_traverse_exports") +load(":jvm_compile.bzl", "kt_jvm_compile") + +# TODO: Use this function in all Kotlin rules +def _make_default_info(ctx, direct_files, propagated_attrs): + # Collect runfiles from deps + transitive_runfiles = [] + for p in common.collect_providers(DefaultInfo, propagated_attrs): + transitive_runfiles.append(p.data_runfiles.files) + transitive_runfiles.append(p.default_runfiles.files) + runfiles = ctx.runfiles( + files = direct_files, + transitive_files = depset(transitive = transitive_runfiles), + collect_default = True, # handles data attribute + ) + + return DefaultInfo( + files = depset(direct_files), + runfiles = runfiles, + ) + +def _jvm_library_impl(ctx): + kt_jvm_toolchain = kt_jvm_toolchains.get(ctx) + + for target in ctx.attr.runtime_deps: + if JavaInfo in target: + pass + elif CcInfo not in target: + fail("Unexpected runtime dependency (must provide JavaInfo or CcInfo): " + str(target.label)) + + if not ctx.files.srcs and not ctx.files.common_srcs and not ctx.attr.exports and not ctx.attr.exported_plugins: + fail("Expected a source-bearing or an export-oriented target:\n" + + "One of {srcs, common_srcs, exports, exported_plugins} of target %s must be non empty" % ctx.label) + + compile_result = kt_jvm_compile( + ctx, + output = ctx.outputs.jar, + srcs = ctx.files.srcs, + common_srcs = ctx.files.common_srcs, + deps = ctx.attr.deps, + plugins = ctx.attr.plugins, + exported_plugins = ctx.attr.exported_plugins, + runtime_deps = ctx.attr.runtime_deps, + exports = ctx.attr.exports, + javacopts = ctx.attr.javacopts, + kotlincopts = merge_kotlincopts(ctx), + neverlink = False, + testonly = ctx.attr.testonly, + android_lint_plugins = [p[JavaInfo] for p in ctx.attr._android_lint_plugins], + manifest = None, + merged_manifest = None, + resource_files = [], + classpath_resources = ctx.files.resources, + kt_toolchain = kt_jvm_toolchain, + java_toolchain = java_toolchains.get(ctx), + disable_lint_checks = ctx.attr.disable_lint_checks, + rule_family = common.RULE_FAMILY.JVM_LIBRARY, + ) + + java_info = compile_result.java_info + + # Collect and validate proguard_specs + # TODO should also propagate IDL proguard_specs when there's idl_srcs + transitive_proguard_configs = common.collect_proguard_specs( + ctx, + ctx.files.proguard_specs, + ctx.attr.deps + ctx.attr.exports, + kt_jvm_toolchain.proguard_whitelister, + ) + + # Create OutputGroupInfo + output_groups = dict( + _validation = depset(compile_result.validations), + _source_jars = depset( + java_info.source_jars, + transitive = [java_info.transitive_source_jars], + ), + _direct_source_jars = depset(java_info.source_jars), + _hidden_top_level_INTERNAL_ = depset( + transitive = [ + info._hidden_top_level_INTERNAL_ + for info in common.collect_providers( + OutputGroupInfo, + ctx.attr.deps + ctx.attr.exports, + ) + ] + [transitive_proguard_configs], + ), + ) + + return [ + java_info, + ProguardSpecProvider(transitive_proguard_configs), + _make_default_info( + ctx, + [ctx.outputs.jar], + propagated_attrs = ctx.attr.deps + ctx.attr.runtime_deps + ctx.attr.exports, + ), + OutputGroupInfo(**output_groups), + coverage_common.instrumented_files_info( + ctx, + source_attributes = ["srcs", "common_srcs"], + dependency_attributes = ["data", "deps", "resources", "runtime_deps"], + ), + ] + +_KT_JVM_LIBRARY_ATTRS = dicts.add( + java_toolchains.attrs, + kotlincopts_attrs(), + kt_jvm_toolchains.attrs, + common_srcs = attr.label_list( + allow_files = common.KT_FILE_TYPES, + allow_empty = True, + doc = """The list of common multi-platform source files that are processed to create + the target.""", + ), + data = attr.label_list( + allow_files = True, + ), + deps = attr.label_list( + allow_rules = common.ALLOWED_JVM_RULES, + providers = [ + # Each provider-set expands on allow_rules + ], + aspects = [ + kt_traverse_exports.aspect, + ], + doc = """The list of libraries this library directly depends on at compile-time. For Java + and Kotlin libraries listed, the Jars they build as well as the transitive closure + of their `deps` and `exports` will be on the compile-time classpath for this rule; + also, the transitive closure of their `deps`, `runtime_deps`, and `exports` will be + on the runtime classpath (excluding dependencies only depended on as `neverlink`). + + Note on strict_deps: any Java type explicitly or implicitly referred to in `srcs` + must be included here. This is a stronger requirement than what is enforced for + `java_library`. Any build failures resulting from this requirement will include the + missing dependencies and a command to fix the rule.""", + ), + disable_lint_checks = attr.string_list( + doc = """A list of lint checks to be skipped for this target.""", + ), + exported_plugins = attr.label_list( + providers = [ + [JavaPluginInfo], + [KtCompilerPluginInfo], + ], + cfg = "exec", + doc = """JVM plugins to export to users. + + Every plugin listed will run during compliations that depend on this target, as + if it were listed directly in that target's `plugins` attribute. `java_*` targets + will not run kotlinc plugins""", + ), + exports = attr.label_list( + allow_rules = common.ALLOWED_JVM_RULES, + providers = [ + # Each provider-set expands on allow_rules + ], + aspects = [ + kt_traverse_exports.aspect, + ], + doc = """List of libraries treated as if they were part of this library by upstream + Java/Kotlin dependencies, see go/be-java#java_library.exports. These libraries + are **not** automatically also dependencies of this library.""", + ), + javacopts = attr.string_list( + doc = """Additional flags to pass to javac if used as part of this rule, which is the case + if `.java` `srcs` are provided or annotation processors generate sources for this + rule.""", + ), + plugins = attr.label_list( + providers = [ + [JavaPluginInfo], + [KtCompilerPluginInfo], + ], + cfg = "exec", + doc = """JVM plugins to run during compilation. + + Every plugin listed will run whenever this library is built. Resources generated by the + plugin will be included in the output JAR. A library may also inherit plugins from + dependencies that use `exported_plugins`.""", + ), + proguard_specs = attr.label_list( + allow_files = True, + doc = """Proguard specifications to go along with this library.""", + ), + resources = attr.label_list( + allow_files = True, + doc = """A list of data files to include in the Jar, see + go/be#java_library.resources.""", + ), + runtime_deps = attr.label_list( + allow_rules = common.ALLOWED_JVM_RULES, + providers = [ + # Each provider-set expands on allow_rules + [CcInfo], # for JNI / native dependencies + ], + aspects = [ + kt_traverse_exports.aspect, + ], + doc = """Runtime-only dependencies.""", + ), + srcs = attr.label_list( + allow_files = common.KT_JVM_FILE_TYPES, + allow_empty = True, + doc = """The list of source files that are processed to create the target. + To support circular dependencies, this can include `.kt` and `.java` files.""", + ), + _android_lint_plugins = attr.label_list( + providers = [ + [JavaInfo], + ], + cfg = "exec", + ), +) + +kt_jvm_library_helper = rule( + attrs = _KT_JVM_LIBRARY_ATTRS, + fragments = ["java"], + outputs = dict( + jar = "lib%{name}.jar", + srcjar = "lib%{name}-src.jar", # implicit declared output for consistency with java_library + ), + provides = [JavaInfo], + implementation = _jvm_library_impl, + toolchains = [kt_jvm_toolchains.type], + doc = """This rule compiles Kotlin (and Java) sources into a Jar file. Most Java-like libraries + and binaries can depend on this rule, and this rule can in turn depend on Kotlin and + Java libraries. This rule supports a subset of attributes supported by `java_library`. + In addition to documentation provided as part of this rule, please also refer to their + documentation as part of `java_library`.""", +) diff --git a/kotlin/jvm_test.bzl b/kotlin/jvm_test.bzl new file mode 100644 index 0000000..b7270e2 --- /dev/null +++ b/kotlin/jvm_test.bzl @@ -0,0 +1,85 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Kotlin macro for building and running tests on a JVM.""" + +load(":jvm_library.bzl", "kt_jvm_library") +load("//bazel:stubs.bzl", "register_extension_info") + +def _lib_name(name): + return "%s_DO_NOT_DEPEND_LIB" % name + +def kt_jvm_test( + name, + custom_kotlincopts = None, + deps = None, + disable_lint_checks = None, + features = None, + javacopts = None, + plugins = None, + runtime_deps = None, + srcs = None, + resources = None, + tags = None, + **kwargs): + """Wrapper around kt_jvm_library and java_test to conveniently declare tests written in Kotlin. + + Use of this rule is discouraged for simple unit tests, which should instead use + go/junit-test-suites or other, more efficient ways of compiling and running unit tests. + + Args: + name: Name of the target. + custom_kotlincopts: Additional flags to pass to Kotlin compiler defined by kt_compiler_opt. + deps: A list of dependencies. + disable_lint_checks: A list of AndroidLint checks to be skipped. + features: A list of enabled features, see go/be#common.features. + javacopts: Additional flags to pass to javac if used. + plugins: Java annotation processors to run at compile-time. + runtime_deps: A list of runtime dependencies. + srcs: A list of sources to compile. + tags: A list of string tags passed to generated targets. + **kwargs: Additional parameters to pass on to generated java_test, see go/be-java#java_test. + """ + if srcs: + runtime_deps = [_lib_name(name)] + (runtime_deps or []) + + kt_jvm_library( + name = _lib_name(name), + srcs = srcs, + resources = resources, + deps = deps, + plugins = plugins, + javacopts = javacopts, + custom_kotlincopts = custom_kotlincopts, + disable_lint_checks = disable_lint_checks, + tags = tags, + features = features, + testonly = 1, + visibility = ["//visibility:private"], + ) + elif deps: + fail("deps specified without sources. Use runtime_deps instead to specify any dependencies needed to run this test.") + + native.java_test( + name = name, + runtime_deps = runtime_deps, + tags = tags, + features = features, + **kwargs + ) + +register_extension_info( + extension = kt_jvm_test, + label_regex_for_dep = "{extension_name}_DO_NOT_DEPEND_LIB", +) diff --git a/kotlin/rules.bzl b/kotlin/rules.bzl new file mode 100644 index 0000000..8d0188b --- /dev/null +++ b/kotlin/rules.bzl @@ -0,0 +1,25 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Kotlin rules.""" + +load("//kotlin:jvm_import.bzl", _kt_jvm_import = "kt_jvm_import") +load("//kotlin:jvm_library.bzl", _kt_jvm_library = "kt_jvm_library") +load("//kotlin:jvm_test.bzl", _kt_jvm_test = "kt_jvm_test") + +kt_jvm_import = _kt_jvm_import + +kt_jvm_library = _kt_jvm_library + +kt_jvm_test = _kt_jvm_test diff --git a/kotlin/traverse_exports.bzl b/kotlin/traverse_exports.bzl new file mode 100644 index 0000000..e579080 --- /dev/null +++ b/kotlin/traverse_exports.bzl @@ -0,0 +1,121 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Combined aspect for all rules_kotlin behaviours that need to traverse exports.""" + +load(":compiler_plugin.bzl", "kt_compiler_plugin_visitor") +load(":direct_jdeps.bzl", "kt_direct_jdeps_visitor") +load(":forbidden_deps.bzl", "kt_forbidden_deps_visitor") +load(":friend_jars.bzl", "kt_friend_jars_visitor") +load(":java_plugin.internal.bzl", "java_plugin_visitor") + +# java_xxx_proto_library don't populate java_outputs but we can get them through +# required_aspect_providers from their proto_library deps. +_DEPS_AS_EXPORTS_RULES = [ + "java_proto_library", + "java_lite_proto_library", + "java_mutable_proto_library", +] + +_NO_SRCS_DEPS_AS_EXPORTS_RULES = [ + "android_library", + "proto_library", +] + +# visitor = struct[T]( +# name = string, +# visit_target = function(Target, ctx.rule): list[T], +# filter_edge = None|(function(src: ?, dest: Target): bool), +# process_unvisited_target = None|(function(Target): list[T]), +# finish_expansion = None|(function(depset[T]): depset[T]), +# ) +_VISITORS = [ + kt_forbidden_deps_visitor, + kt_direct_jdeps_visitor, + kt_compiler_plugin_visitor, + kt_friend_jars_visitor, + java_plugin_visitor, +] + +_KtTraverseExportsInfo = provider( + doc = "depsets for transitive info about exports", + fields = { + v.name: ("depset[%s]" % v.name) + for v in _VISITORS + }, +) + +_EMPTY_KT_TRAVERSE_EXPORTS_INFO = _KtTraverseExportsInfo(**{ + v.name: depset() + for v in _VISITORS +}) + +def _aspect_impl(target, ctx): + if not (JavaInfo in target): + # Ignore non-JVM targets. This also chops-up the + # traversal domain at these targets. + # TODO: Supoprt non-JVM targets for KMP + return _EMPTY_KT_TRAVERSE_EXPORTS_INFO + + exports = [] + exports.extend(getattr(ctx.rule.attr, "exports", [])) # exports list is frozen + if ctx.rule.kind in _DEPS_AS_EXPORTS_RULES: + exports.extend(ctx.rule.attr.deps) + elif ctx.rule.kind in _NO_SRCS_DEPS_AS_EXPORTS_RULES and not ctx.rule.attr.srcs: + exports.extend(ctx.rule.attr.deps) + + return _KtTraverseExportsInfo(**{ + v.name: depset( + direct = v.visit_target(target, ctx.rule), + transitive = [ + getattr(e[_KtTraverseExportsInfo], v.name) + for e in exports + if (not v.filter_edge or v.filter_edge(target, e)) + ], + ) + for v in _VISITORS + }) + +_aspect = aspect( + implementation = _aspect_impl, + provides = [_KtTraverseExportsInfo], + # Transitively check exports, since they are effectively directly depended on. + # "deps" needed for rules that treat deps as exports (usually absent srcs). + attr_aspects = ["exports", "deps"], + required_aspect_providers = [JavaInfo], # to get at JavaXxxProtoAspects' JavaInfos +) + +def _create_visitor_expand(visitor): + def _visitor_expand(targets, root = None): + direct = [] + transitive = [] + for t in targets: + if (not visitor.filter_edge or visitor.filter_edge(root, t)): + if _KtTraverseExportsInfo in t: + transitive.append(getattr(t[_KtTraverseExportsInfo], visitor.name)) + elif visitor.process_unvisited_target: + direct.extend(visitor.process_unvisited_target(t)) + + expanded_set = depset(direct = direct, transitive = transitive) + return visitor.finish_expansion(expanded_set) if visitor.finish_expansion else expanded_set + + return _visitor_expand + +kt_traverse_exports = struct( + aspect = _aspect, + **{ + "expand_" + v.name: _create_visitor_expand(v) + for v in _VISITORS + } +) diff --git a/tests/BUILD b/tests/BUILD new file mode 100644 index 0000000..414af7d --- /dev/null +++ b/tests/BUILD @@ -0,0 +1,13 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/tests/analysis/BUILD b/tests/analysis/BUILD new file mode 100644 index 0000000..b927805 --- /dev/null +++ b/tests/analysis/BUILD @@ -0,0 +1,27 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Analysis Tests + +load("//tests/analysis:jvm_compile_test.bzl", jvm_compile_test_suite = "test_suite") +load("//tests/analysis:jvm_import_test.bzl", jvm_import_test_suite = "test_suite") +load("//tests/analysis:jvm_library_test.bzl", jvm_library_test_suite = "test_suite") + +licenses(["notice"]) + +jvm_compile_test_suite(name = "jvm_compile_tests") + +jvm_library_test_suite(name = "jvm_library_tests") + +jvm_import_test_suite(name = "jvm_import_tests") diff --git a/tests/analysis/assert_failure_test.bzl b/tests/analysis/assert_failure_test.bzl new file mode 100644 index 0000000..b266c2a --- /dev/null +++ b/tests/analysis/assert_failure_test.bzl @@ -0,0 +1,30 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""An assertion for analysis failure.""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") + +def _assert_failure_test_impl(ctx): + env = analysistest.begin(ctx) + asserts.expect_failure(env, ctx.attr.msg_contains) + return analysistest.end(env) + +assert_failure_test = analysistest.make( + _assert_failure_test_impl, + expect_failure = True, + attrs = dict( + msg_contains = attr.string(mandatory = True), + ), +) diff --git a/tests/analysis/compiler_plugin/BUILD b/tests/analysis/compiler_plugin/BUILD new file mode 100644 index 0000000..0c1f9b6 --- /dev/null +++ b/tests/analysis/compiler_plugin/BUILD @@ -0,0 +1,23 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +licenses(["notice"]) + +genrule( + name = "empty_jar", + outs = ["empty.jar"], + cmd = """$(location @bazel_tools//tools/zip:zipper) c $@ "assets/_empty=" """, + tools = ["@bazel_tools//tools/zip:zipper"], + visibility = ["//tests/analysis/compiler_plugin:__subpackages__"], +) diff --git a/tests/analysis/compiler_plugin/forbidden_target/BUILD b/tests/analysis/compiler_plugin/forbidden_target/BUILD new file mode 100644 index 0000000..9f751fa --- /dev/null +++ b/tests/analysis/compiler_plugin/forbidden_target/BUILD @@ -0,0 +1,19 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//kotlin:compiler_plugin.bzl", "kt_compiler_plugin") +load("//tests/analysis:assert_failure_test.bzl", "assert_failure_test") +load("//tests/analysis:util.bzl", "ONLY_FOR_ANALYSIS_TEST_TAGS") + +licenses(["notice"]) diff --git a/tests/analysis/compiler_plugin/propagation/BUILD b/tests/analysis/compiler_plugin/propagation/BUILD new file mode 100644 index 0000000..0c6fe19 --- /dev/null +++ b/tests/analysis/compiler_plugin/propagation/BUILD @@ -0,0 +1,79 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//kotlin:compiler_plugin.bzl", "kt_compiler_plugin") +load(":assert_propagation_test.bzl", "assert_propagation_test") + +licenses(["notice"]) + +assert_propagation_test( + name = "f", + expected_plugin_ids = ["1"], + deps = [":e"], +) + +assert_propagation_test( + name = "e", + expected_plugin_ids = [], + exports = [":a"], +) + +assert_propagation_test( + name = "d", + expected_plugin_ids = [ + "1", + "2", + ], + deps = [ + ":a", + ":b", + ], +) + +assert_propagation_test( + name = "c", + expected_plugin_ids = ["2"], + deps = [":b"], +) + +assert_propagation_test( + name = "b", + expected_plugin_ids = ["1"], + exported_plugins = [":2"], + deps = [":a"], +) + +assert_propagation_test( + name = "a", + expected_plugin_ids = [], + exported_plugins = [":1"], +) + +kt_compiler_plugin( + name = "1", + jar = "//tests/analysis/compiler_plugin:empty_jar", + plugin_id = "1", +) + +kt_compiler_plugin( + name = "2", + jar = "//tests/analysis/compiler_plugin:empty_jar", + plugin_id = "2", +) + +kt_compiler_plugin( + name = "3", + jar = "//tests/analysis/compiler_plugin:empty_jar", + plugin_id = "3", +) diff --git a/tests/analysis/compiler_plugin/propagation/assert_propagation_test.bzl b/tests/analysis/compiler_plugin/propagation/assert_propagation_test.bzl new file mode 100644 index 0000000..fe8c9dc --- /dev/null +++ b/tests/analysis/compiler_plugin/propagation/assert_propagation_test.bzl @@ -0,0 +1,56 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Rule for asserting plugin propagation.""" + +load("@bazel_skylib//lib:sets.bzl", "sets") +load("@bazel_skylib//rules:build_test.bzl", "build_test") +load("//kotlin:traverse_exports.bzl", "kt_traverse_exports") + +def _assert_propagation_impl(ctx): + expected_ids = sets.make(ctx.attr.expected_plugin_ids) + actual_ids = sets.make([ + p.plugin_id + for p in kt_traverse_exports.expand_compiler_plugins(ctx.attr.deps).to_list() + ]) + + if not sets.is_equal(expected_ids, actual_ids): + fail("Expected IDs %s, actual IDs %s" % (sets.to_list(expected_ids), sets.to_list(actual_ids))) + + return [ + # Needed for kt_traverse_exports.aspect + JavaInfo( + compile_jar = ctx.file._empty_jar, + output_jar = ctx.file._empty_jar, + ), + ] + +_assert_propagation = rule( + implementation = _assert_propagation_impl, + attrs = dict( + exports = attr.label_list(), + exported_plugins = attr.label_list(), + expected_plugin_ids = attr.string_list(), + deps = attr.label_list(aspects = [kt_traverse_exports.aspect]), + _empty_jar = attr.label( + allow_single_file = True, + default = "//tests/analysis/compiler_plugin:empty_jar", + ), + ), +) + +def assert_propagation_test(name, **kwargs): + _assert_propagation(name = name, **kwargs) + + build_test(name = name + "_build", targets = [name]) diff --git a/tests/analysis/compiler_plugin/provider_ctor/BUILD b/tests/analysis/compiler_plugin/provider_ctor/BUILD new file mode 100644 index 0000000..fb5acbc --- /dev/null +++ b/tests/analysis/compiler_plugin/provider_ctor/BUILD @@ -0,0 +1,19 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//tests/analysis:assert_failure_test.bzl", "assert_failure_test") +load("//tests/analysis:util.bzl", "ONLY_FOR_ANALYSIS_TEST_TAGS") +load(":fake_compiler_plugin.bzl", "kt_fake_compiler_plugin") + +licenses(["notice"]) diff --git a/tests/analysis/compiler_plugin/provider_ctor/fake_compiler_plugin.bzl b/tests/analysis/compiler_plugin/provider_ctor/fake_compiler_plugin.bzl new file mode 100644 index 0000000..d4a6bac --- /dev/null +++ b/tests/analysis/compiler_plugin/provider_ctor/fake_compiler_plugin.bzl @@ -0,0 +1,37 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""A fake impl of kt_compiler_plugin.""" + +load("//kotlin:compiler_plugin.bzl", "KtCompilerPluginInfo") + +def _kt_fake_compiler_plugin_impl(ctx): + return [ + KtCompilerPluginInfo( + plugin_id = "fake", + jar = ctx.file._jar, + args = [], + ), + ] + +kt_fake_compiler_plugin = rule( + implementation = _kt_fake_compiler_plugin_impl, + attrs = dict( + _jar = attr.label( + allow_single_file = True, + default = "//tests/analysis/compiler_plugin:empty_jar", + ), + ), + provides = [KtCompilerPluginInfo], +) diff --git a/tests/analysis/compiler_plugin/provider_output/BUILD b/tests/analysis/compiler_plugin/provider_output/BUILD new file mode 100644 index 0000000..4769965 --- /dev/null +++ b/tests/analysis/compiler_plugin/provider_output/BUILD @@ -0,0 +1,58 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//kotlin:compiler_plugin.bzl", "kt_compiler_plugin") +load("//tests/analysis:util.bzl", "create_file") +load("@bazel_skylib//rules:build_test.bzl", "build_test") +load(":assert_compiler_plugin_test.bzl", "assert_compiler_plugin_test") + +licenses(["notice"]) + +assert_compiler_plugin_test( + name = "example_plugin_test", + expected_args = [ + "plugin:com.google.example:key=value", + ], + expected_id = "com.google.example", + expected_jar = "//tests/analysis/compiler_plugin:empty_jar", + target_under_test = ":example_plugin", +) + +build_test( + name = "example_plugin_in_java_library_build_test", + targets = [ + ":example_plugin_in_java_library", + ], +) + +java_library( + name = "example_plugin_in_java_library", + srcs = [create_file( + name = "Tmp.java", + content = """ + @SuppressWarnings("DefaultPackage") + class Tmp { } + """, + )], + plugins = [":example_plugin"], +) + +kt_compiler_plugin( + name = "example_plugin", + args = { + "key": "value", + }, + jar = "//tests/analysis/compiler_plugin:empty_jar", + plugin_id = "com.google.example", +) diff --git a/tests/analysis/compiler_plugin/provider_output/assert_compiler_plugin_test.bzl b/tests/analysis/compiler_plugin/provider_output/assert_compiler_plugin_test.bzl new file mode 100644 index 0000000..9b2951e --- /dev/null +++ b/tests/analysis/compiler_plugin/provider_output/assert_compiler_plugin_test.bzl @@ -0,0 +1,37 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""An assertion on kt_compiler_plugin analysis.""" + +load("//kotlin:compiler_plugin.bzl", "KtCompilerPluginInfo") +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") + +def _test_impl(ctx): + env = analysistest.begin(ctx) + info = ctx.attr.target_under_test[KtCompilerPluginInfo] + + asserts.equals(env, info.plugin_id, ctx.attr.expected_id) + asserts.equals(env, info.jar, ctx.file.expected_jar) + asserts.equals(env, info.args, ctx.attr.expected_args) + + return analysistest.end(env) + +assert_compiler_plugin_test = analysistest.make( + impl = _test_impl, + attrs = dict( + expected_id = attr.string(), + expected_jar = attr.label(allow_single_file = True, cfg = "exec"), + expected_args = attr.string_list(), + ), +) diff --git a/tests/analysis/jvm_compile_test.bzl b/tests/analysis/jvm_compile_test.bzl new file mode 100644 index 0000000..b361f5a --- /dev/null +++ b/tests/analysis/jvm_compile_test.bzl @@ -0,0 +1,390 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Kotlin kt_jvm_compile API test.""" + +load("//kotlin:traverse_exports.bzl", "kt_traverse_exports") +load("//kotlin:jvm_compile.bzl", "kt_jvm_compile") +load("//kotlin:common.bzl", "common") +load("//tests/analysis:util.bzl", "ONLY_FOR_ANALYSIS_TEST_TAGS", "create_dir", "create_file") +load("//toolchains/kotlin_jvm:java_toolchains.bzl", "java_toolchains") +load("//toolchains/kotlin_jvm:kt_jvm_toolchains.bzl", "kt_jvm_toolchains") +load("@bazel_skylib//rules:build_test.bzl", "build_test") +load(":assert_failure_test.bzl", "assert_failure_test") + +def _impl(ctx): + # As additional capabilites need to be tested, this rule should support + # additional fields/attributes. + result = kt_jvm_compile( + ctx, + output = ctx.outputs.jar, + srcs = ctx.files.srcs, + common_srcs = ctx.files.common_srcs, + deps = ctx.attr.deps, + plugins = [], + exported_plugins = [], + runtime_deps = [], + exports = ctx.attr.exports, + javacopts = [], + kotlincopts = [], + neverlink = False, + testonly = False, + android_lint_plugins = [], + manifest = None, + merged_manifest = None, + resource_files = [], + rule_family = ctx.attr.rule_family, + kt_toolchain = kt_jvm_toolchains.get(ctx), + java_toolchain = java_toolchains.get(ctx), + disable_lint_checks = [], + r_java = ctx.attr.r_java[JavaInfo] if ctx.attr.r_java else None, + ) + return [result.java_info] + +_kt_jvm_compile = rule( + implementation = _impl, + attrs = dict( + srcs = attr.label_list( + allow_files = True, + ), + common_srcs = attr.label_list( + allow_files = True, + ), + deps = attr.label_list( + aspects = [kt_traverse_exports.aspect], + providers = [JavaInfo], + ), + exports = attr.label_list( + aspects = [kt_traverse_exports.aspect], + providers = [JavaInfo], + ), + rule_family = attr.int( + default = common.RULE_FAMILY.UNKNOWN, + ), + r_java = attr.label( + providers = [JavaInfo], + ), + _java_toolchain = attr.label( + default = Label( + "@bazel_tools//tools/jdk:current_java_toolchain", + ), + ), + ), + fragments = ["java"], + outputs = dict( + jar = "lib%{name}.jar", + ), + toolchains = [kt_jvm_toolchains.type], +) + +def _test_kt_jvm_compile_using_kt_jvm_compile_with_r_java(): + test_name = "kt_jvm_compile_using_kt_jvm_compile_with_r_java_test" + + native.java_library( + name = "foo_resources", + srcs = [create_file( + name = test_name + "/java/com/foo/R.java", + content = """ +package com.foo; + +public final class R { + public static final class string { + public static int a_string=0x00000001; + public static int b_string=0x00000002; + } +} +""", + )], + ) + + _kt_jvm_compile( + name = "kt_jvm_compile_with_r_java", + srcs = [create_file( + name = test_name + "/AString.kt", + content = """ +package test + +import com.foo.R.string.a_string + +fun aString(): String = "a_string=" + a_string +""", + )], + r_java = ":foo_resources", + ) + + _kt_jvm_compile( + name = "kt_jvm_compile_using_kt_jvm_compile_with_r_java", + srcs = [create_file( + name = test_name + "/ABString.kt", + content = """ +package test + +import com.foo.R.string.b_string + +fun bString(): String = "b_string=" + b_string + +fun abString(): String = aString() + bString() +""", + )], + deps = [":kt_jvm_compile_with_r_java"], + ) + + # If a failure occurs, it will be at build time. + build_test( + name = test_name, + targets = [":kt_jvm_compile_using_kt_jvm_compile_with_r_java"], + ) + return test_name + +def _test_kt_jvm_compile_with_illegal_r_java(): + test_name = "kt_jvm_compile_with_illegal_r_java_test" + + native.java_library( + name = "foo", + srcs = [create_file( + name = test_name + "/java/com/foo/Foo.java", + content = """ +package com.foo; + +public class Foo {} +""", + )], + ) + _kt_jvm_compile( + name = "kt_jvm_compile_with_illegal_r_java", + srcs = [create_file( + name = test_name + "/AString.kt", + content = """ +package test + +import com.foo.Foo + +fun bar(): String = "Bar" +""", + )], + tags = ONLY_FOR_ANALYSIS_TEST_TAGS, + r_java = ":foo", + ) + assert_failure_test( + name = test_name, + target_under_test = ":kt_jvm_compile_with_illegal_r_java", + msg_contains = "illegal dependency provided for r_java", + ) + return test_name + +def _test_kt_jvm_compile_with_r_java_as_first_dep(): + test_name = "kt_jvm_compile_with_r_java_as_first_dep_test" + + # Note: The R from an android_library must be the first dependency in + # the classpath to prevent another libraries R from being used for + # compilation. If the ordering is incorrect, compiletime failures will + # occur as the depot relies on this ordering. + + native.java_library( + name = "foo_with_symbol_resources", + srcs = [create_file( + name = test_name + "/with_symbol/java/com/foo/R.java", + content = """ +package com.foo; + +public final class R { + public static final class string { + public static int a_string=0x00000001; + } +} +""", + )], + ) + + native.java_library( + name = "foo_without_symbol_resources", + srcs = [create_file( + name = test_name + "/without_symbol/java/com/foo/R.java", + content = """ +package com.foo; + +public final class R { + public static final class string { + } +} +""", + )], + ) + + _kt_jvm_compile( + name = "kt_jvm_compile_with_r_java_as_first_dep", + srcs = [create_file( + name = test_name + "/AString.kt", + content = """ +package test + +import com.foo.R.string.a_string + +fun aString(): String = "a_string=" + a_string +""", + )], + r_java = ":foo_with_symbol_resources", + deps = [":foo_without_symbol_resources"], + ) + + # If a failure occurs, it will be at build time. + build_test( + name = test_name, + targets = [":kt_jvm_compile_with_r_java_as_first_dep"], + ) + return test_name + +def _test_kt_jvm_compile_without_srcs_for_android(): + test_name = "kt_jvm_compile_without_srcs_for_android_test" + + # This is a common case for rules like android_library where Kotlin sources + # could be empty, due to the rule being used for resource processing. For + # this scenario, historically, rules continue to produce empty Jars. + _kt_jvm_compile( + name = "kt_jvm_compile_without_srcs_for_android", + rule_family = common.RULE_FAMILY.ANDROID_LIBRARY, + ) + + # If a failure occurs, it will be at build time. + build_test( + name = test_name, + targets = [":kt_jvm_compile_without_srcs_for_android"], + ) + return test_name + +def _test_kt_jvm_compile_without_srcs_for_jvm(): + test_name = "kt_jvm_compile_without_srcs_for_jvm_test" + + _kt_jvm_compile( + name = "kt_jvm_compile_without_srcs_for_jvm", + srcs = [], + common_srcs = [], + exports = [], + tags = ONLY_FOR_ANALYSIS_TEST_TAGS, + ) + assert_failure_test( + name = test_name, + target_under_test = ":kt_jvm_compile_without_srcs_for_jvm", + msg_contains = "Expected one of (srcs, common_srcs, exports) is not empty", + ) + return test_name + +def _test_kt_jvm_compile_without_srcs_and_with_exports(): + test_name = "kt_jvm_compile_without_srcs_and_with_exports_test" + + _kt_jvm_compile( + name = "bar_lib", + srcs = [create_file( + name = test_name + "/Bar.kt", + content = """ +package test + +fun bar(): String = "Bar" +""", + )], + ) + + _kt_jvm_compile( + name = "kt_jvm_compile_without_srcs_and_with_exports", + exports = [":bar_lib"], + ) + + _kt_jvm_compile( + name = "foo_bar_lib", + srcs = [create_file( + name = test_name + "/FooBar.kt", + content = """ +package test + +fun fooBar(): String = "Foo" + bar() +""", + )], + deps = [":kt_jvm_compile_without_srcs_and_with_exports"], + ) + + # If a failure occurs, it will be at build time. + build_test( + name = test_name, + targets = [":foo_bar_lib"], + ) + return test_name + +def _test_kt_jvm_compile_unsupported_src_artifacts(): + test_name = "kt_jvm_compile_unsupported_src_artifacts_test" + + kt_src = create_file( + name = test_name + "/src.kt", + content = "", + ) + kt_dir = create_dir( + name = test_name + "/kotlin", + subdir = "", + srcs = [create_file( + name = test_name + "/dir.kt", + content = "", + )], + ) + java_src = create_file( + name = test_name + "/src.java", + content = "", + ) + java_dir = create_dir( + name = test_name + "/java", + subdir = "", + srcs = [create_file( + name = test_name + "/dir.java", + content = "", + )], + ) + java_srcjar = create_file( + name = test_name + "/java.srcjar", + content = "", + ) + _kt_jvm_compile( + name = test_name + "_expected_lib", + srcs = [kt_src, kt_dir, java_src, java_dir, java_srcjar], + tags = ONLY_FOR_ANALYSIS_TEST_TAGS, + ) + + unexpected_file = create_file( + name = test_name + "/src.unexpected", + content = "", + ) + _kt_jvm_compile( + name = test_name + "_unexpected_lib", + srcs = [unexpected_file], + deps = [test_name + "_expected_lib"], + tags = ONLY_FOR_ANALYSIS_TEST_TAGS, + ) + + assert_failure_test( + name = test_name, + target_under_test = test_name + "_unexpected_lib", + msg_contains = "/src.unexpected", + ) + return test_name + +def test_suite(name = None): + native.test_suite( + name = name, + tests = [ + _test_kt_jvm_compile_unsupported_src_artifacts(), + _test_kt_jvm_compile_using_kt_jvm_compile_with_r_java(), + _test_kt_jvm_compile_with_illegal_r_java(), + _test_kt_jvm_compile_with_r_java_as_first_dep(), + _test_kt_jvm_compile_without_srcs_for_android(), + _test_kt_jvm_compile_without_srcs_for_jvm(), + _test_kt_jvm_compile_without_srcs_and_with_exports(), + ], + ) diff --git a/tests/analysis/jvm_import_test.bzl b/tests/analysis/jvm_import_test.bzl new file mode 100644 index 0000000..a3bfd19 --- /dev/null +++ b/tests/analysis/jvm_import_test.bzl @@ -0,0 +1,168 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Kotlin kt_jvm_import rule tests.""" + +load("//kotlin:jvm_import.bzl", "kt_jvm_import") +load("//kotlin:jvm_library.bzl", "kt_jvm_library") +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("//tests/analysis:util.bzl", "ONLY_FOR_ANALYSIS_TEST_TAGS", "create_file") +load(":assert_failure_test.bzl", "assert_failure_test") + +def _impl(ctx): + env = analysistest.begin(ctx) + asserts.true( + env, + JavaInfo in ctx.attr.target_under_test, + "kt_jvm_import did not produce JavaInfo provider.", + ) + asserts.true( + env, + ProguardSpecProvider in ctx.attr.target_under_test, + "kt_jvm_import did not produce ProguardSpecProvider provider.", + ) + return analysistest.end(env) + +_test = analysistest.make(_impl) + +def _test_kt_jvm_import(): + test_name = "kt_jvm_import_test" + native.java_library( + name = "jar1", + srcs = [], + ) + kt_jvm_import( + name = test_name + "_tut", + jars = [ + "libjar1.jar", + ], + srcjar = "libjar1-src.jar", + ) + _test( + name = test_name, + target_under_test = test_name + "_tut", + ) + return test_name + +def _test_kt_jvm_import_no_srcjar(): + test_name = "kt_jvm_import_no_srcjar_test" + native.java_library( + name = "jar3", + srcs = [], + ) + kt_jvm_import( + name = test_name + "_tut", + jars = [ + "libjar3.jar", + ], + ) + _test( + name = test_name, + target_under_test = test_name + "_tut", + ) + return test_name + +def _test_kt_jvm_import_with_srcjar_ext(): + test_name = "kt_jvm_import_test_with_srcjar_ext" + native.java_library( + name = "jar2", + srcs = [], + ) + native.genrule( + name = "gen_jar2_srcjar", + cmd = "touch $@", + outs = ["libjar2.srcjar"], + ) + kt_jvm_import( + name = test_name + "_tut", + jars = [ + "libjar2.jar", + ], + srcjar = ":libjar2.srcjar", + ) + _test( + name = test_name, + target_under_test = test_name + "_tut", + ) + return test_name + +def _test_kt_jvm_import_with_runtime_deps(): + test_name = "kt_jvm_import_with_runtime_deps" + native.java_library( + name = test_name + "_dep", + srcs = [], + ) + kt_jvm_import( + name = test_name + "_tut", + jars = [ + "lib%s_dep.jar" % test_name, + ], + runtime_deps = [ + test_name + "_dep", + ], + ) + _test( + name = test_name, + target_under_test = test_name + "_tut", + ) + return test_name + +def _test_kt_jvm_import_with_proguard_specs(): + test_name = "kt_jvm_import_with_proguard_specs" + native.java_library( + name = test_name + "_jar", + srcs = [], + ) + + kt_jvm_import( + name = test_name + "_tut", + jars = [ + "lib%s_jar.jar" % test_name, + ], + proguard_specs = [ + create_file( + name = test_name + "/salutations.pgcfg", + content = """ +-keep class * { + *** greeting(); +} +""", + ), + ], + ) + _test( + name = test_name, + target_under_test = test_name + "_tut", + ) + return test_name + +def _mock_jar(test_name, i): + """Creates a Jar named after the given inputs and returns its name.""" + native.java_library( + name = "%s_mock%s" % (test_name, i), + srcs = [], + ) + return "lib%s_mock%s.jar" % (test_name, i) + +def test_suite(name = None): + native.test_suite( + name = name, + tests = [ + _test_kt_jvm_import(), + _test_kt_jvm_import_with_srcjar_ext(), + _test_kt_jvm_import_no_srcjar(), + _test_kt_jvm_import_with_runtime_deps(), + _test_kt_jvm_import_with_proguard_specs(), + ], + ) diff --git a/tests/analysis/jvm_library/friends/BUILD b/tests/analysis/jvm_library/friends/BUILD new file mode 100644 index 0000000..3c4a7db --- /dev/null +++ b/tests/analysis/jvm_library/friends/BUILD @@ -0,0 +1,105 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//kotlin:rules.bzl", "kt_jvm_library") +load("//tests/analysis:jvm_library_test.bzl", "jvm_library_test") +load("//tests/analysis:util.bzl", "ONLY_FOR_ANALYSIS_TEST_TAGS") + +package( + default_testonly = True, + default_visibility = ["//tests/analysis/jvm_library/friends:__subpackages__"], +) + +licenses(["notice"]) + +jvm_library_test( + name = "no_kt_exported_friend_trans_package_test", + expected_friend_jar_names = [], + target_under_test = ":no_kt_exported_friend_trans_package", +) + +kt_jvm_library( + name = "no_kt_exported_friend_trans_package", + srcs = ["Input.kt"], + tags = ONLY_FOR_ANALYSIS_TEST_TAGS, + deps = [ + # Exports :friend from this package + "//tests/analysis/jvm_library/friends/sub:kt_exports_friend", + ], +) + +jvm_library_test( + name = "has_java_exported_friend_in_package_test", + expected_friend_jar_names = [ + "libjava_exports_friend-hjar.jar", + "friend-compile.jar", + ], + target_under_test = ":has_java_exported_friend_in_package", +) + +kt_jvm_library( + name = "has_java_exported_friend_in_package", + srcs = ["Input.kt"], + tags = ONLY_FOR_ANALYSIS_TEST_TAGS, + deps = [":java_exports_friend"], +) + +java_library( + name = "java_exports_friend", + srcs = ["Input.java"], + tags = ONLY_FOR_ANALYSIS_TEST_TAGS, + exports = [":friend"], +) + +jvm_library_test( + name = "has_kt_exported_friend_in_package_test", + expected_friend_jar_names = [ + "kt_exports_friend-compile.jar", + "friend-compile.jar", + ], + target_under_test = ":has_kt_exported_friend_in_package", +) + +kt_jvm_library( + name = "has_kt_exported_friend_in_package", + srcs = ["Input.kt"], + tags = ONLY_FOR_ANALYSIS_TEST_TAGS, + deps = [":kt_exports_friend"], +) + +kt_jvm_library( + name = "kt_exports_friend", + srcs = ["Input.kt"], + tags = ONLY_FOR_ANALYSIS_TEST_TAGS, + exports = [":friend"], +) + +jvm_library_test( + name = "has_direct_friend_in_package_test", + expected_friend_jar_names = ["friend-compile.jar"], + target_under_test = ":has_direct_friend_in_package", +) + +kt_jvm_library( + name = "has_direct_friend_in_package", + srcs = ["Input.kt"], + tags = ONLY_FOR_ANALYSIS_TEST_TAGS, + deps = [":friend"], +) + +kt_jvm_library( + name = "friend", + srcs = ["Input.kt"], + tags = ONLY_FOR_ANALYSIS_TEST_TAGS, +) diff --git a/tests/analysis/jvm_library/friends/Input.java b/tests/analysis/jvm_library/friends/Input.java new file mode 100644 index 0000000..5bf1d18 --- /dev/null +++ b/tests/analysis/jvm_library/friends/Input.java @@ -0,0 +1,19 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package test; + +final class Input {} diff --git a/tests/analysis/jvm_library/friends/Input.kt b/tests/analysis/jvm_library/friends/Input.kt new file mode 100644 index 0000000..b1a99cb --- /dev/null +++ b/tests/analysis/jvm_library/friends/Input.kt @@ -0,0 +1,17 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package test diff --git a/tests/analysis/jvm_library/friends/sub/BUILD b/tests/analysis/jvm_library/friends/sub/BUILD new file mode 100644 index 0000000..7c26e59 --- /dev/null +++ b/tests/analysis/jvm_library/friends/sub/BUILD @@ -0,0 +1,60 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//kotlin:rules.bzl", "kt_jvm_library") +load("//tests/analysis:jvm_library_test.bzl", "jvm_library_test") +load("//tests/analysis:util.bzl", "ONLY_FOR_ANALYSIS_TEST_TAGS") + +package( + default_testonly = True, + default_visibility = ["//tests/analysis/jvm_library/friends:__subpackages__"], +) + +licenses(["notice"]) + +jvm_library_test( + name = "no_kt_exported_friend_cross_package_test", + expected_friend_jar_names = [ + "kt_exports_friend-compile.jar", + # Absent # "friend-compile.jar" + ], + target_under_test = ":no_kt_exported_friend_cross_package", +) + +kt_jvm_library( + name = "no_kt_exported_friend_cross_package", + srcs = ["Input.kt"], + tags = ONLY_FOR_ANALYSIS_TEST_TAGS, + deps = [":kt_exports_friend"], +) + +kt_jvm_library( + name = "kt_exports_friend", + srcs = ["Input.kt"], + tags = ONLY_FOR_ANALYSIS_TEST_TAGS, + exports = ["//tests/analysis/jvm_library/friends:friend"], +) + +jvm_library_test( + name = "no_direct_friend_cross_package_test", + expected_friend_jar_names = [], + target_under_test = ":no_direct_friend_cross_package", +) + +kt_jvm_library( + name = "no_direct_friend_cross_package", + srcs = ["Input.kt"], + tags = ONLY_FOR_ANALYSIS_TEST_TAGS, + deps = ["//tests/analysis/jvm_library/friends:friend"], +) diff --git a/tests/analysis/jvm_library/friends/sub/Input.kt b/tests/analysis/jvm_library/friends/sub/Input.kt new file mode 100644 index 0000000..4c87a1e --- /dev/null +++ b/tests/analysis/jvm_library/friends/sub/Input.kt @@ -0,0 +1,17 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package test.sub diff --git a/tests/analysis/jvm_library_test.bzl b/tests/analysis/jvm_library_test.bzl new file mode 100644 index 0000000..a73bbbc --- /dev/null +++ b/tests/analysis/jvm_library_test.bzl @@ -0,0 +1,838 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Kotlin kt_jvm_library rule tests.""" + +load("//kotlin:jvm_library.bzl", "kt_jvm_library") +load("//tests/analysis:util.bzl", "ONLY_FOR_ANALYSIS_TEST_TAGS", "create_file", "get_action_arg") +load("@bazel_skylib//lib:sets.bzl", "sets") +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load(":assert_failure_test.bzl", "assert_failure_test") + +_DEFAULT_LIST = ["__default__"] + +def _test_impl(ctx): + env = analysistest.begin(ctx) + actions = analysistest.target_actions(env) + actual = ctx.attr.target_under_test + expected = ctx.attr.expected + + asserts.true( + env, + JavaInfo in actual, + "kt_jvm_library did not produce JavaInfo provider.", + ) + asserts.true( + env, + ProguardSpecProvider in actual, + "Expected a ProguardSpecProvider provider.", + ) + + if "data" in expected: + expected_data = expected["data"] + actual_data = _extract_data_runfiles(actual) + + asserts.new_set_equals( + env, + sets.make(expected_data), + sets.make(actual_data), + """ + FAIL: kt_jvm_library did not produce the expected data dependencies. + EXPECTED: %s + ACTUAL: %s + """ % (expected_data, actual_data), + ) + + expected_exports = [] + for target in ctx.attr.expected_exports: + asserts.equals( + env, + 1, + len(target[JavaInfo].full_compile_jars.to_list()), + "Not a single compile-time Jar: %s" % target.label, + ) + expected_exports.extend(target[JavaInfo].full_compile_jars.to_list()) + actual_exports = actual[JavaInfo].full_compile_jars.to_list() + + # TODO: fail if there are *un*expected exports, maybe by making sure + # that the actual exports are exactly the expected ones plus the Jar(s) + # produced by this JavaInfo. + for expected_export in expected_exports: + asserts.true( + env, + expected_export in actual_exports, + """ + kt_jvm_library did not export %s + actual: %s + """ % (expected_export, actual_exports), + ) + + asserts.equals( + env, + ctx.attr.expected_exported_processor_classes, + actual[JavaInfo].plugins.processor_classes.to_list(), + ) + + if ctx.attr.expected_friend_jar_names != _DEFAULT_LIST: + friend_paths_arg = get_action_arg(actions, "Kt2JavaCompile", "-Xfriend-paths=") + friend_jar_names = [p.rsplit("/", 1)[1] for p in friend_paths_arg.split(",")] if friend_paths_arg else [] + asserts.set_equals(env, sets.make(ctx.attr.expected_friend_jar_names), sets.make(friend_jar_names)) + + return analysistest.end(env) + +_test = analysistest.make( + impl = _test_impl, + attrs = dict( + expected = attr.string_list_dict(), + expected_exports = attr.label_list(), + expected_exported_processor_classes = attr.string_list( + doc = "Annotation processors reported as to be run on depending targets", + ), + expected_processor_classes = attr.string_list( + doc = "Annotation processors reported as run on the given target", + ), + expected_friend_jar_names = attr.string_list( + doc = "Names of all -Xfriend-paths= JARs", + default = _DEFAULT_LIST, + ), + expect_processor_classpath = attr.bool(), + ), +) + +jvm_library_test = _test + +def _coverage_test_impl(ctx): + env = analysistest.begin(ctx) + target_under_test = analysistest.target_under_test(env) + instrumented_files_info = target_under_test[InstrumentedFilesInfo] + instrumented_files = instrumented_files_info.instrumented_files.to_list() + asserts.equals( + env, + ctx.attr.expected_instrumented_file_basenames, + [file.basename for file in instrumented_files], + ) + return analysistest.end(env) + +_coverage_test = analysistest.make( + impl = _coverage_test_impl, + attrs = { + "expected_instrumented_file_basenames": attr.string_list(), + }, + config_settings = { + "//command_line_option:collect_code_coverage": "1", + "//command_line_option:instrument_test_targets": "1", + "//command_line_option:instrumentation_filter": "+tests/analysis[:/]", + }, +) + +def _extract_data_runfiles(target): + return [f.basename for f in target[DefaultInfo].data_runfiles.files.to_list()] + +def _test_kt_jvm_library_with_deps(): + test_name = "kt_jvm_library_with_deps_test" + + kt_jvm_library( + name = test_name + "_kt_dep", + srcs = [create_file( + name = test_name + "/Hello.kt", + content = """ +package test + +fun hello(): String = "Hello!" +""", + )], + ) + native.java_library( + name = test_name + "_java_dep", + srcs = ["testinputs/Foo.java"], + ) + kt_jvm_library( + name = test_name + "_tut", + srcs = [ + create_file( + name = test_name + "/Hi.kt", + content = """ +package test + +fun hi(): String = "Hi!" +""", + ), + "testinputs/Bar.java", + ], + deps = [ + test_name + "_kt_dep", + test_name + "_java_dep", + ], + ) + _test( + name = test_name, + target_under_test = test_name + "_tut", + ) + return test_name + +def _test_kt_jvm_library_no_deps(): + test_name = "kt_jvm_library_no_deps_test" + create_file( + name = test_name + "/Salutations.kt", + content = """ +package test + +fun greeting(): String = "Hello World!" +""", + ) + kt_jvm_library( + name = test_name + "_tut", + srcs = [ + "testinputs/Bar.java", + test_name + "/Salutations.kt", + ], + ) + _test( + name = test_name, + target_under_test = test_name + "_tut", + ) + return test_name + +def _test_kt_jvm_library_with_only_common_srcs(): + test_name = "kt_jvm_library_only_common_srcs_test" + create_file( + name = test_name + "/Salutations.kt", + content = """ +package test + +fun greeting(): String = "Hello World!" +""", + ) + kt_jvm_library( + name = test_name + "_tut", + common_srcs = [ + test_name + "/Salutations.kt", + ], + ) + _test( + name = test_name, + target_under_test = test_name + "_tut", + ) + return test_name + +def _test_kt_jvm_library_no_java_srcs(): + test_name = "kt_jvm_library_no_java_srcs_test" + create_file( + name = test_name + "/Salutations.kt", + content = """ +package test + +fun greeting(): String = "Hello World!" +""", + ) + kt_jvm_library( + name = test_name + "_tut", + srcs = [ + test_name + "/Salutations.kt", + ], + ) + _test( + name = test_name, + target_under_test = test_name + "_tut", + ) + return test_name + +def _test_kt_jvm_library_no_kt_srcs(): + test_name = "kt_jvm_library_no_kt_srcs_test" + kt_jvm_library( + name = test_name + "_tut", + srcs = [ + "testinputs/Bar.java", + ], + ) + _test( + name = test_name, + target_under_test = test_name + "_tut", + ) + return test_name + +def _test_kt_jvm_library_with_runtime_deps(): + test_name = "kt_jvm_library_with_runtime_deps_test" + create_file( + name = test_name + "/Salutations.kt", + content = """ +package test + +fun greeting(): String = "Hello World!" +""", + ) + native.java_library( + name = test_name + "_dep", + srcs = [], + ) + kt_jvm_library( + name = test_name + "_tut", + srcs = [ + test_name + "/Salutations.kt", + ], + runtime_deps = [ + test_name + "_dep", + ], + ) + _test( + name = test_name, + target_under_test = test_name + "_tut", + ) + return test_name + +def _test_kt_jvm_library_with_proguard_specs(): + test_name = "kt_jvm_library_with_proguard_specs_test" + create_file( + name = test_name + "/Salutations.kt", + content = """ +package test + +fun greeting(): String = "Hello World!" +""", + ) + create_file( + name = test_name + "/salutations.pgcfg", + content = """ +-keep class * { + *** greeting(); +} +""", + ) + kt_jvm_library( + name = test_name + "_tut", + srcs = [ + test_name + "/Salutations.kt", + ], + proguard_specs = [ + test_name + "/salutations.pgcfg", + ], + ) + _test( + name = test_name, + target_under_test = test_name + "_tut", + ) + return test_name + +def _test_kt_jvm_library_with_resources(): + test_name = "kt_jvm_library_with_resources_test" + create_file( + name = test_name + "/Salutations.kt", + content = """ +package test + +fun greeting(): String = "Hello World!" +""", + ) + create_file( + name = test_name + "/salutations.txt", + content = """ +Hi! +""", + ) + kt_jvm_library( + name = test_name + "_tut", + srcs = [ + test_name + "/Salutations.kt", + "testinputs/Foo.java", + ], + resources = [ + test_name + "/salutations.txt", + ], + ) + _test( + name = test_name, + target_under_test = test_name + "_tut", + ) + return test_name + +def _test_kt_jvm_library_with_data(): + test_name = "kt_jvm_library_with_data_test" + kt_jvm_lib_name = test_name + "_tut" + + data_txt = create_file( + name = test_name + "data.txt", + content = """ +Hello World! +""", + ) + + # Kotlin file + muchdata_kt = create_file( + name = test_name + "/MuchData.kt", + content = """ +package test + +import java.io.File + +fun greeting(): String = File("data.txt").readText() +""", + ) + + kt_jvm_library( + name = kt_jvm_lib_name, + srcs = [muchdata_kt], + data = [data_txt], + ) + + _test( + name = test_name, + target_under_test = kt_jvm_lib_name, + expected = dict( + data = [ + data_txt, + # libX.jar is always in data_runfiles as well - just append it. + "lib%s.jar" % kt_jvm_lib_name, + ], + ), + ) + return test_name + +def _test_kt_jvm_library_with_plugin(): + test_name = "kt_jvm_library_with_plugin_test" + create_file( + name = test_name + "/Salutations.kt", + content = """ +package test + +fun greeting(): String = "Hello World!" +""", + ) + + kt_jvm_library( + name = test_name + "_tut", + srcs = [ + test_name + "/Salutations.kt", + ], + # Need a working plugin so it can run for the test. + plugins = ["//bazel:auto_value_plugin"], + ) + + _test( + name = test_name, + target_under_test = test_name + "_tut", + expected_processor_classes = ["com.google.auto.value.processor.AutoValueProcessor"], + expect_processor_classpath = True, + ) + return test_name + +def _test_kt_jvm_library_no_kt_srcs_with_plugin(): + test_name = "kt_jvm_library_no_kt_srcs_with_plugin_test" + native.java_plugin( + name = "%s_plugin" % test_name, + processor_class = test_name, + srcs = ["testinputs/Foo.java"], # induce processor_classpath + ) + kt_jvm_library( + name = test_name + "_tut", + srcs = ["testinputs/Bar.java"], + plugins = [":%s_plugin" % test_name], + tags = ONLY_FOR_ANALYSIS_TEST_TAGS, + ) + _test( + name = test_name, + target_under_test = test_name + "_tut", + expected_processor_classes = [test_name], + expect_processor_classpath = True, + ) + return test_name + +def _test_kt_jvm_library_with_non_processor_plugin(): + test_name = "kt_jvm_library_with_non_processor_plugin_test" + create_file( + name = test_name + "/Salutations.kt", + content = """ +package test + +fun greeting(): String = "Hello World!" +""", + ) + + native.java_plugin( + # no processor_class + name = "%s_plugin" % test_name, + srcs = ["testinputs/Foo.java"], + ) + kt_jvm_library( + name = test_name + "_tut", + srcs = [ + test_name + "/Salutations.kt", + ], + plugins = [":%s_plugin" % test_name], + ) + + _test( + name = test_name, + target_under_test = test_name + "_tut", + expected_processor_classes = [], # no processor class so no processing + expect_processor_classpath = True, # expect java_plugin's Jar + ) + return test_name + +def _test_kt_jvm_library_with_exported_plugin(): + test_name = "kt_jvm_library_with_exported_plugin_test" + create_file( + name = test_name + "/Salutations.kt", + content = """ +package test + +fun greeting(): String = "Hello World!" +""", + ) + native.java_plugin( + name = "%s_plugin" % test_name, + processor_class = test_name, + ) + kt_jvm_library( + name = test_name + "_tut", + srcs = [ + test_name + "/Salutations.kt", + ], + exported_plugins = [":%s_plugin" % test_name], + ) + + _test( + name = test_name, + target_under_test = test_name + "_tut", + expected_exported_processor_classes = [test_name], + expected_processor_classes = [], # exported plugin should *not* run on _tut itself + ) + return test_name + +def _test_kt_jvm_library_dep_on_exported_plugin(): + test_name = "kt_jvm_library_dep_on_exported_plugin_test" + create_file( + name = test_name + "/Salutations.kt", + content = """ +package test + +fun greeting(): String = "Hello World!" +""", + ) + + native.java_plugin( + name = "%s_plugin" % test_name, + processor_class = test_name, + srcs = ["testinputs/Foo.java"], # induce processor_classpath + ) + kt_jvm_library( + name = "%s_exports_plugin" % test_name, + srcs = [test_name + "/Salutations.kt"], + exported_plugins = [":%s_plugin" % test_name], + ) + kt_jvm_library( + name = test_name + "_tut", + srcs = [ + test_name + "/Salutations.kt", + ], + deps = [":%s_exports_plugin" % test_name], + tags = ONLY_FOR_ANALYSIS_TEST_TAGS, + ) + + _test( + name = test_name, + target_under_test = test_name + "_tut", + expected_processor_classes = [test_name], + expect_processor_classpath = True, + ) + return test_name + +def _test_kt_jvm_library_java_dep_on_exported_plugin(): + test_name = "kt_jvm_library_java_dep_on_exported_plugin_test" + create_file( + name = test_name + "/Salutations.kt", + content = """ +package test + +fun greeting(): String = "Hello World!" +""", + ) + native.java_plugin( + name = "%s_plugin" % test_name, + processor_class = test_name, + srcs = ["testinputs/Foo.java"], # induce processor_classpath + ) + native.java_library( + name = "%s_exports_plugin" % test_name, + exported_plugins = [":%s_plugin" % test_name], + ) + kt_jvm_library( + name = test_name + "_tut", + srcs = [ + test_name + "/Salutations.kt", + ], + deps = [":%s_exports_plugin" % test_name], + tags = ONLY_FOR_ANALYSIS_TEST_TAGS, + ) + + _test( + name = test_name, + target_under_test = test_name + "_tut", + expected_processor_classes = [test_name], + expect_processor_classpath = True, + ) + return test_name + +def _test_kt_jvm_library_with_exports(): + test_name = "kt_jvm_library_with_exports_test" + create_file( + name = test_name + "/Salutations.kt", + content = """ +package test + +fun greeting(): String = "Hello World!" +""", + ) + kt_jvm_library( + name = test_name + "_exp", + srcs = [test_name + "/Salutations.kt"], + ) + native.java_library( + name = test_name + "_javaexp", + srcs = ["testinputs/Foo.java"], # need file here so we get a Jar + ) + kt_jvm_library( + name = test_name + "_tut", + srcs = [ + test_name + "/Salutations.kt", + ], + exports = [ + ":%s_exp" % test_name, + ":%s_javaexp" % test_name, + ], + ) + _test( + name = test_name, + target_under_test = test_name + "_tut", + expected_exports = [ + ":%s_exp" % test_name, + ":%s_javaexp" % test_name, + ], + ) + return test_name + +def _test_kt_jvm_library_with_export_that_exports_plugin(): + test_name = "kt_jvm_library_with_export_that_exports_plugin_test" + create_file( + name = test_name + "/Salutations.kt", + content = """ +package test + +fun greeting(): String = "Hello World!" +""", + ) + native.java_plugin( + name = "%s_plugin" % test_name, + processor_class = test_name, + srcs = ["testinputs/Foo.java"], # induce processor_classpath + ) + kt_jvm_library( + name = "%s_exports_plugin" % test_name, + exported_plugins = [":%s_plugin" % test_name], + srcs = [test_name + "/Salutations.kt"], + ) + kt_jvm_library( + name = test_name + "_tut", + srcs = [ + test_name + "/Salutations.kt", + ], + exports = [":%s_exports_plugin" % test_name], + ) + _test( + name = test_name, + target_under_test = test_name + "_tut", + expected_exports = [":%s_exports_plugin" % test_name], + expected_exported_processor_classes = [test_name], + ) + return test_name + +def _test_kt_jvm_library_with_java_export_that_exports_plugin(): + test_name = "kt_jvm_library_with_java_export_that_exports_plugin_test" + create_file( + name = test_name + "/Salutations.kt", + content = """ +package test + +fun greeting(): String = "Hello World!" +""", + ) + native.java_plugin( + name = "%s_plugin" % test_name, + processor_class = test_name, + srcs = ["testinputs/Foo.java"], # induce processor_classpath + ) + native.java_library( + name = "%s_exports_plugin" % test_name, + exported_plugins = [":%s_plugin" % test_name], + ) + kt_jvm_library( + name = test_name + "_tut", + srcs = [ + test_name + "/Salutations.kt", + ], + exports = [":%s_exports_plugin" % test_name], + ) + _test( + name = test_name, + target_under_test = test_name + "_tut", + expected_exports = [], # _exports_plugin has no compile/runtime Jars + expected_exported_processor_classes = [test_name], + ) + return test_name + +def _test_forbidden_nano_dep(): + test_name = "kt_jvm_library_forbidden_nano_test" + + kt_jvm_library( + name = test_name + "_tut", + srcs = [test_name + "/Ignored.kt"], + deps = [test_name + "_fake_nano_proto_lib"], + tags = [ + "manual", + "nobuilder", + ], + ) + native.java_library( + name = test_name + "_fake_nano_proto_lib", + srcs = [], + tags = ["nano_proto_library"], + ) + assert_failure_test( + name = test_name, + target_under_test = test_name + "_tut", + msg_contains = test_name + "_fake_nano_proto_lib : nano_proto_library", + ) + return test_name + +def _test_forbidden_nano_export(): + test_name = "kt_jvm_library_forbidden_nano_export_test" + + kt_jvm_library( + name = test_name + "_tut", + srcs = [test_name + "/Ignored.kt"], + deps = [test_name + "_export"], + tags = [ + "manual", + "nobuilder", + ], + ) + native.java_library( + name = test_name + "_export", + exports = [test_name + "_fake_nano_proto_lib"], + ) + native.java_library( + name = test_name + "_fake_nano_proto_lib", + srcs = [], + tags = ["nano_proto_library"], + ) + assert_failure_test( + name = test_name, + target_under_test = test_name + "_tut", + msg_contains = test_name + "_fake_nano_proto_lib : nano_proto_library", + ) + return test_name + +def _test_kt_jvm_library_with_no_sources(): + test_name = "kt_jvm_library_with_no_sources_test" + + kt_jvm_library( + name = test_name + "_tut", + tags = [ + "manual", + "nobuilder", + ], + ) + tut_label = str(Label("//tests/analysis:kt_jvm_library_with_no_sources_test_tut")) + assert_failure_test( + name = test_name, + target_under_test = test_name + "_tut", + msg_contains = "One of {srcs, common_srcs, exports, exported_plugins} of target " + tut_label + " must be non empty", + ) + return test_name + +def _test_kt_jvm_library_coverage(): + test_name = "kt_jvm_library_coverage" + kt_jvm_library( + name = test_name + "_tut", + srcs = ["testinputs/Srcs.kt"], + common_srcs = ["testinputs/CommonSrcs.kt"], + deps = [":{}_deps".format(test_name)], + runtime_deps = [":{}_runtime_deps".format(test_name)], + data = [":{}_data".format(test_name)], + resources = [":{}_resources".format(test_name)], + testonly = True, + ) + native.java_library( + name = test_name + "_deps", + srcs = ["testinputs/Deps.java"], + testonly = True, + ) + native.java_library( + name = test_name + "_runtime_deps", + srcs = ["testinputs/RuntimeDeps.java"], + testonly = True, + ) + native.java_binary( + name = test_name + "_data", + main_class = "Data", + srcs = ["testinputs/Data.java"], + testonly = True, + ) + native.java_binary( + name = test_name + "_resources", + main_class = "Resources", + srcs = ["testinputs/Resources.java"], + testonly = True, + ) + _coverage_test( + name = test_name, + target_under_test = test_name + "_tut", + expected_instrumented_file_basenames = [ + "Data.java", + "Deps.java", + "Resources.java", + "RuntimeDeps.java", + "Srcs.kt", + "CommonSrcs.kt", + ], + ) + return test_name + +def test_suite(name): + native.test_suite( + name = name, + tests = [ + _test_forbidden_nano_dep(), + _test_forbidden_nano_export(), + _test_kt_jvm_library_dep_on_exported_plugin(), + _test_kt_jvm_library_java_dep_on_exported_plugin(), + _test_kt_jvm_library_no_deps(), + _test_kt_jvm_library_no_java_srcs(), + _test_kt_jvm_library_no_kt_srcs(), + _test_kt_jvm_library_no_kt_srcs_with_plugin(), + _test_kt_jvm_library_with_data(), + _test_kt_jvm_library_with_deps(), + _test_kt_jvm_library_with_export_that_exports_plugin(), + _test_kt_jvm_library_with_exported_plugin(), + _test_kt_jvm_library_with_exports(), + _test_kt_jvm_library_with_java_export_that_exports_plugin(), + _test_kt_jvm_library_with_no_sources(), + _test_kt_jvm_library_with_non_processor_plugin(), + _test_kt_jvm_library_with_only_common_srcs(), + _test_kt_jvm_library_with_plugin(), + _test_kt_jvm_library_with_proguard_specs(), + _test_kt_jvm_library_with_resources(), + _test_kt_jvm_library_with_runtime_deps(), + _test_kt_jvm_library_coverage(), + ], + ) diff --git a/tests/analysis/testinputs/Bar.java b/tests/analysis/testinputs/Bar.java new file mode 100644 index 0000000..c69a114 --- /dev/null +++ b/tests/analysis/testinputs/Bar.java @@ -0,0 +1,21 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package testinputs; + +public class Bar { + public Bar() {} +} diff --git a/tests/analysis/testinputs/CommonSrcs.kt b/tests/analysis/testinputs/CommonSrcs.kt new file mode 100644 index 0000000..932e704 --- /dev/null +++ b/tests/analysis/testinputs/CommonSrcs.kt @@ -0,0 +1,19 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package testinputs + +class CommonSrcs diff --git a/tests/analysis/testinputs/Data.java b/tests/analysis/testinputs/Data.java new file mode 100644 index 0000000..d8e161f --- /dev/null +++ b/tests/analysis/testinputs/Data.java @@ -0,0 +1,21 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package testinputs; + +final class Data { + private Data() {} +} diff --git a/tests/analysis/testinputs/Deps.java b/tests/analysis/testinputs/Deps.java new file mode 100644 index 0000000..7f5237f --- /dev/null +++ b/tests/analysis/testinputs/Deps.java @@ -0,0 +1,21 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package testinputs; + +final class Deps { + private Deps() {} +} diff --git a/tests/analysis/testinputs/Foo.java b/tests/analysis/testinputs/Foo.java new file mode 100644 index 0000000..249811a --- /dev/null +++ b/tests/analysis/testinputs/Foo.java @@ -0,0 +1,21 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package testinputs; + +public class Foo { + public Foo() {} +} diff --git a/tests/analysis/testinputs/Resources.java b/tests/analysis/testinputs/Resources.java new file mode 100644 index 0000000..cbf6e7c --- /dev/null +++ b/tests/analysis/testinputs/Resources.java @@ -0,0 +1,21 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package testinputs; + +final class Resources { + private Resources() {} +} diff --git a/tests/analysis/testinputs/RuntimeDeps.java b/tests/analysis/testinputs/RuntimeDeps.java new file mode 100644 index 0000000..5515a7a --- /dev/null +++ b/tests/analysis/testinputs/RuntimeDeps.java @@ -0,0 +1,21 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package testinputs; + +final class RuntimeDeps { + private RuntimeDeps() {} +} diff --git a/tests/analysis/testinputs/Srcs.kt b/tests/analysis/testinputs/Srcs.kt new file mode 100644 index 0000000..89ca40c --- /dev/null +++ b/tests/analysis/testinputs/Srcs.kt @@ -0,0 +1,19 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package testinputs + +class Srcs diff --git a/tests/analysis/util.bzl b/tests/analysis/util.bzl new file mode 100644 index 0000000..cec0cc3 --- /dev/null +++ b/tests/analysis/util.bzl @@ -0,0 +1,97 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Some utils""" + +# Mark targets that's aren't expected to build, but are needed for analysis test assertions. +ONLY_FOR_ANALYSIS_TEST_TAGS = ["manual", "nobuilder", "only_for_analysis_test"] + +def create_file(name, content): + if content.startswith("\n"): + content = content[1:-1] + + native.genrule( + name = "gen_" + name, + outs = [name], + cmd = """ +cat > $@ <<EOF +%s +EOF +""" % content, + ) + + return name + +def _create_dir_impl(ctx): + dir = ctx.actions.declare_directory(ctx.attr.name) + if ctx.files.srcs: + ctx.actions.run_shell( + command = "mkdir -p {0} && cp {1} {0}".format( + dir.path + "/" + ctx.attr.subdir, + " ".join([s.path for s in ctx.files.srcs]), + ), + inputs = ctx.files.srcs, + outputs = [dir], + ) + else: + ctx.actions.run_shell( + command = "mkdir -p {0}".format( + dir.path + "/" + ctx.attr.subdir, + ), + inputs = ctx.files.srcs, + outputs = [dir], + ) + return [DefaultInfo(files = depset([dir]))] + +_create_dir = rule( + implementation = _create_dir_impl, + attrs = dict( + subdir = attr.string(), + srcs = attr.label_list(allow_files = True), + ), +) + +def create_dir(name, subdir, srcs): + _create_dir( + name = name, + subdir = subdir, + srcs = srcs, + ) + return name + +def get_action_arg(actions, mnemonic, arg_name): + """Get a named arg from a specific action + + Args: + actions: [List[Action]] + mnemonic: [string] Identify the action whose args to search + arg_name: [string] + + Returns: + [Optional[string]] The arg value, or None if it couldn't be found + """ + menmonic_actions = [a for a in actions if a.mnemonic == mnemonic] + if len(menmonic_actions) == 0: + return None + elif len(menmonic_actions) > 1: + fail("Expected a single '%s' action" % mnemonic) + + mnemonic_action = menmonic_actions[0] + arg_values = [a for a in mnemonic_action.argv if a.startswith(arg_name)] + if len(arg_values) == 0: + return None + elif len(arg_values) > 1: + fail("Expected a single '%s' arg" % arg_name) + + return arg_values[0][len(arg_name):] diff --git a/tests/jvm/java/beer/BUILD b/tests/jvm/java/beer/BUILD new file mode 100644 index 0000000..9a50474 --- /dev/null +++ b/tests/jvm/java/beer/BUILD @@ -0,0 +1,45 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//kotlin:rules.bzl", "kt_jvm_library", "kt_jvm_test") + +licenses(["notice"]) + +kt_jvm_library( + name = "beer_lib", + srcs = ["Beer.kt"], + deps = [ + "@dagger", + "@maven//:javax_inject_jsr330_api", + ], +) + +kt_jvm_test( + name = "beer", + main_class = "beer.BeerKt", + tags = ["darwin_x86_64_compatible"], + runtime_deps = [":beer_lib"], +) + +# Regression test for b/123767247 +sh_test( + name = "build_data_test", + srcs = ["build_data_test.sh"], + data = [ + ":libbeer_lib.jar", + ], + env = { + "TEST_JAR": "$(location :libbeer_lib.jar)", + }, +) diff --git a/tests/jvm/java/beer/Beer.kt b/tests/jvm/java/beer/Beer.kt new file mode 100644 index 0000000..5bac323 --- /dev/null +++ b/tests/jvm/java/beer/Beer.kt @@ -0,0 +1,186 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package beer + +import dagger.Binds +import dagger.Component +import dagger.Lazy +import dagger.Module +import dagger.Provides +import javax.inject.Inject +import javax.inject.Singleton + +interface Grains { + val name: String +} + +interface Hops { + val name: String +} + +interface Yeast { + val name: String +} + +interface Kettle { + fun steep() + fun heat() + fun boil() + fun cool() + fun ferment() + fun addGrains(grains: Grains) + fun addHops(hops: Hops) + fun addYeast(yeast: Yeast) + val isBoiling: Boolean + val hasCooled: Boolean + val isDone: Boolean +} + +interface Storage { + fun store() +} + +class PilsnerMalt +@Inject constructor() : Grains { + override val name get() = "Pilsner Malt" +} + +class Spalt +@Inject constructor() : Hops { + override val name get() = "Spalt" +} + +class Wyeast +@Inject constructor() : Yeast { + override val name get() = "Wyeast 2565 Kölsch" +} + +class BrewPot : Kettle { + var boiling: Boolean = false + var cool: Boolean = true + var done: Boolean = false + + override fun addGrains(grains: Grains) { + println("Adding grains: " + grains.name) + } + + override fun steep() { + println("=> Steeping") + } + + override fun heat() { + println("=> Heating") + this.cool = false + } + + override fun boil() { + println("=> Boiling") + this.boiling = true + } + + override fun cool() { + println("=> Cooling") + this.boiling = false + this.cool = true + } + + override fun addHops(hops: Hops) { + println("Adding hops: " + hops.name) + } + + override fun ferment() { + println("=> Fermenting") + this.done = true + } + + override fun addYeast(yeast: Yeast) { + println("Adding yeast: " + yeast.name) + } + + override val isBoiling get() = boiling + override val hasCooled get() = cool + override val isDone get() = done +} + +class Bottler +@Inject constructor( + private val kettle: Kettle +) : Storage { + override fun store() { + if (kettle.isDone) { + println("=> bottling") + } + } +} + +class BeerBrewer +@Inject constructor( + private val kettle: Lazy<Kettle>, + private val bottler: Bottler, + private val grains: Grains, + private val hops: Hops, + private val yeast: Yeast +) { + fun brew() { + kettle.get().apply { + addGrains(grains) + steep() + heat() + boil() + if (isBoiling) addHops(hops) + cool() + if (hasCooled) addYeast(yeast) + ferment() + } + bottler.store() + } +} + +@Module +abstract class CommercialEquipmentModule { + @Binds + abstract fun provideStorage(storage: Bottler): Storage +} + +@Module(includes = [CommercialEquipmentModule::class]) +class BrewingEquipmentModule { + @Provides @Singleton + fun provideKettle(): Kettle = BrewPot() +} + +@Module +interface KolschRecipeModule { + @Binds + fun bindGrains(grains: PilsnerMalt): Grains + + @Binds + fun bindHops(hops: Spalt): Hops + + @Binds + fun bindYeast(yeast: Wyeast): Yeast +} + +@Singleton +@Component(modules = [BrewingEquipmentModule::class, KolschRecipeModule::class]) +interface Brewery { + fun brewery(): BeerBrewer +} + +fun main(args: Array<String>) { + val beer = DaggerBrewery.builder().build() + beer.brewery().brew() +} diff --git a/tests/jvm/java/beer/build_data_test.sh b/tests/jvm/java/beer/build_data_test.sh new file mode 100755 index 0000000..c0c9084 --- /dev/null +++ b/tests/jvm/java/beer/build_data_test.sh @@ -0,0 +1,25 @@ +#!/bin/bash -eu +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# Assert expected files exist +if ! unzip -l "$TEST_JAR" | grep "Kettle.class"; then + exit 1 +fi + +# Assert build data is stripped +if unzip -l "$TEST_JAR" | grep "build-data.properties"; then + exit 1 +fi diff --git a/tests/jvm/java/functions/BUILD b/tests/jvm/java/functions/BUILD new file mode 100644 index 0000000..aa571fe --- /dev/null +++ b/tests/jvm/java/functions/BUILD @@ -0,0 +1,96 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This package tests importing extension functions. +load("//kotlin:rules.bzl", "kt_jvm_import", "kt_jvm_library") + +licenses(["notice"]) + +kt_jvm_library( + name = "car_demo_src_lib", + srcs = ["CarDemo.kt"], + deps = [ + "//tests/jvm/java/functions/car:car_lib", + ], +) + +# This binary is built from source and shouldn't have any issues loading functions. +java_test( + name = "car_src_demo", + main_class = "functions.CarDemo", + tags = ["darwin_x86_64_compatible"], + runtime_deps = [ + ":car_demo_src_lib", + ], +) + +java_import( + name = "car-jar", + jars = ["//tests/jvm/java/functions/car:car_lib-jar"], +) + +kt_jvm_library( + name = "car_demo_jar_lib", + srcs = ["CarDemo.kt"], + deps = [ + ":car-jar", + ], +) + +# This binary includes extension functions defined in an separate jar file, which +# may be problematic if the metadata is stripped by ijar. +java_test( + name = "car_jar_demo", + main_class = "functions.CarDemo", + tags = ["darwin_x86_64_compatible"], + runtime_deps = [ + ":car_demo_jar_lib", + "@kotlinc//:kotlin_stdlib", + ], +) + +kt_jvm_import( + name = "car-inline-jar", + jars = [ + "//tests/jvm/java/functions/car:car_inline_lib-jar", + "//tests/jvm/java/functions/car:car_extra_lib-jar", + ], + deps = [ + ":car-jar", + ], +) + +kt_jvm_library( + name = "car_demo_inline_lib", + srcs = ["CarInlineDemo.kt"], + deps = [ + ":car-inline-jar", + ":car-jar", + ], +) + +# This binary includes inline functions, imported from a jar file using kt_jvm_import. +# Inlined functions cannot be imported using java_import, since ijar strips out functionality. +java_test( + name = "car_inline_demo", + main_class = "functions.CarInlineDemo", + tags = [ + "darwin_x86_64_compatible", + "nozapfhahn", + ], + runtime_deps = [ + ":car_demo_inline_lib", + "@kotlinc//:kotlin_stdlib", + ], +) diff --git a/tests/jvm/java/functions/CarDemo.kt b/tests/jvm/java/functions/CarDemo.kt new file mode 100644 index 0000000..d7b2d0f --- /dev/null +++ b/tests/jvm/java/functions/CarDemo.kt @@ -0,0 +1,33 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package functions + +import functions.car.Car +import functions.car.briefName +import functions.car.specificName +import functions.car.abbrName + +object CarDemo { + + @JvmStatic + fun main(args: Array<String>) { + var car: Car = Car("Honda", "Civic", 2001) + println("brief: ${car.briefName()}") + println("specific: ${car.specificName()}") + println("abbr: ${car.abbrName()}") + } +} diff --git a/tests/jvm/java/functions/CarInlineDemo.kt b/tests/jvm/java/functions/CarInlineDemo.kt new file mode 100644 index 0000000..c18daff --- /dev/null +++ b/tests/jvm/java/functions/CarInlineDemo.kt @@ -0,0 +1,38 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package functions + +import functions.car.Car +import functions.car.abbrName +import functions.car.briefName +import functions.car.customName +import functions.car.reversedName +import functions.car.specificName + +object CarInlineDemo { + + @JvmStatic + fun main(args: Array<String>) { + var car: Car = Car("Honda", "Civic", 2001) + println("brief: ${car.briefName()}") + println("specific: ${car.specificName()}") + println("abbr: ${car.abbrName()}") + println("reversed: ${car.reversedName()}") + val custom: String = car.customName() { year: Int -> year.toString() } + println("custom: $custom") + } +} diff --git a/tests/jvm/java/functions/car/BUILD b/tests/jvm/java/functions/car/BUILD new file mode 100644 index 0000000..81f0f43 --- /dev/null +++ b/tests/jvm/java/functions/car/BUILD @@ -0,0 +1,65 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//kotlin:rules.bzl", "kt_jvm_library") + +package(default_visibility = ["//tests/jvm/java/functions:__subpackages__"]) + +licenses(["notice"]) + +# Make Jar files produced by helper targets visible to tests in parent package +filegroup( + name = "car_lib-jar", + srcs = ["libcar_lib.jar"], +) + +filegroup( + name = "car_inline_lib-jar", + srcs = ["libcar_inline_lib.jar"], +) + +filegroup( + name = "car_extra_lib-jar", + srcs = ["libcar_extra_lib.jar"], +) + +kt_jvm_library( + name = "car_lib", + srcs = [ + "Car.kt", + "CarUtils.kt", + ], + deps = [ + ], +) + +kt_jvm_library( + name = "car_inline_lib", + srcs = [ + "CarInlineUtils.kt", + ], + deps = [ + ":car_lib", + ], +) + +kt_jvm_library( + name = "car_extra_lib", + srcs = [ + "CarExtraUtils.kt", + ], + deps = [ + ":car_lib", + ], +) diff --git a/tests/jvm/java/functions/car/Car.kt b/tests/jvm/java/functions/car/Car.kt new file mode 100644 index 0000000..8bdc445 --- /dev/null +++ b/tests/jvm/java/functions/car/Car.kt @@ -0,0 +1,23 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package functions.car + +data class Car(val make: String, val model: String, val year: Int) + +fun Car.briefName(): String = "$make $model" + +fun Car.specificName(): String = "$year $make $model" diff --git a/tests/jvm/java/functions/car/CarExtraUtils.kt b/tests/jvm/java/functions/car/CarExtraUtils.kt new file mode 100644 index 0000000..7506694 --- /dev/null +++ b/tests/jvm/java/functions/car/CarExtraUtils.kt @@ -0,0 +1,19 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package functions.car + +fun Car.reversedName(): String = "$model $make $year" diff --git a/tests/jvm/java/functions/car/CarInlineUtils.kt b/tests/jvm/java/functions/car/CarInlineUtils.kt new file mode 100644 index 0000000..f55775e --- /dev/null +++ b/tests/jvm/java/functions/car/CarInlineUtils.kt @@ -0,0 +1,19 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package functions.car + +inline fun Car.customName(formatYear: (Int) -> String): String = "${formatYear(year)} $make $model" diff --git a/tests/jvm/java/functions/car/CarUtils.kt b/tests/jvm/java/functions/car/CarUtils.kt new file mode 100644 index 0000000..26ac21b --- /dev/null +++ b/tests/jvm/java/functions/car/CarUtils.kt @@ -0,0 +1,22 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package functions.car + +fun Car.abbrName(): String { + val shortYear: String = year.rem(100).toString().padStart(2, '0') + return "'$shortYear $make $model" +} diff --git a/tests/jvm/java/ijar/BUILD b/tests/jvm/java/ijar/BUILD new file mode 100644 index 0000000..d742e75 --- /dev/null +++ b/tests/jvm/java/ijar/BUILD @@ -0,0 +1,120 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//kotlin:rules.bzl", "kt_jvm_library") + +licenses(["notice"]) + +package(default_testonly = 1) + +java_test( + name = "ijar", + main_class = "ijar.MainKt", + runtime_deps = [":main"], +) + +java_test( + name = "suspense", + test_class = "ijar.SuspendTest", + runtime_deps = [":SuspendTest"], +) + +kt_jvm_library( + name = "inline", + srcs = [ + "InlineCapture.kt", + "InlineInnerClass.kt", + "ReifiedInline.kt", + ], +) + +# Compiling this file by itself triggers synthetic methods needed when compiling +# dependants. These methods carry annotations. +kt_jvm_library( + name = "statics", + srcs = ["JvmStatics.kt"], +) + +kt_jvm_library( + name = "main", + srcs = ["Main.kt"], + deps = [ + ":inline", + ":statics", + ], +) + +kt_jvm_library( + name = "inlined_suspense", + srcs = ["DoubleInline.kt"], +) + +kt_jvm_library( + name = "SuspendTest", + srcs = ["SuspendTest.kt"], + deps = [ + ":inlined_suspense", + "@maven//:com_google_truth_truth", + "@maven//:junit_junit", + ], +) + +java_library( + name = "SamInJava", + srcs = ["SamInJava.java"], +) + +kt_jvm_library( + name = "SamExt", + srcs = ["SamExt.kt"], + deps = [ + ":SamInJava", + ], +) + +kt_jvm_library( + name = "SamExtUser", + srcs = ["SamExtUser.kt"], + deps = [ + ":SamExt", + ":SamInJava", + ], +) + +java_test( + name = "inlinedSamExt", + main_class = "ijar.SamExtUserKt", + runtime_deps = [ + ":SamExtUser", + ], +) + +kt_jvm_library( + name = "InlineWhenMapping", + srcs = ["InlineWhenMapping.kt"], +) + +kt_jvm_library( + name = "InlineWhenMappingUser", + srcs = ["InlineWhenMappingUser.kt"], + deps = [":InlineWhenMapping"], +) + +java_test( + name = "inlineWhenMapping", + main_class = "ijar.InlineWhenMappingUserKt", + runtime_deps = [ + ":InlineWhenMappingUser", + ], +) diff --git a/tests/jvm/java/ijar/DoubleInline.kt b/tests/jvm/java/ijar/DoubleInline.kt new file mode 100644 index 0000000..fd2d89b --- /dev/null +++ b/tests/jvm/java/ijar/DoubleInline.kt @@ -0,0 +1,35 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ijar + +/** + * Regression test for b/143465893: inlining this function requires access to the inner class + * used by the inlined helper [makeAppender], which uses suspend functions. + */ +suspend inline fun doubleInline(also: String, crossinline init: suspend () -> String): String { + return makeAppender { init() }.apply(also) +} + +inline fun makeAppender(crossinline init: suspend () -> String): Suspended<String> { + return object : Suspended<String> { + override suspend fun apply(toAppend: String) = init() + toAppend + } +} + +interface Suspended<T> { + suspend fun apply(input: T): T +} diff --git a/tests/jvm/java/ijar/InlineCapture.kt b/tests/jvm/java/ijar/InlineCapture.kt new file mode 100644 index 0000000..63ce284 --- /dev/null +++ b/tests/jvm/java/ijar/InlineCapture.kt @@ -0,0 +1,27 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ijar + +// Regression test for https://youtrack.jetbrains.net/issue/KT-33604 +fun inlineCapture(s: String): String { + return with(StringBuilder()) { + val o = object { + override fun toString() = s + } + append(o) + }.toString() +} diff --git a/tests/jvm/java/ijar/InlineInnerClass.kt b/tests/jvm/java/ijar/InlineInnerClass.kt new file mode 100644 index 0000000..d12df05 --- /dev/null +++ b/tests/jvm/java/ijar/InlineInnerClass.kt @@ -0,0 +1,35 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ijar + +import java.util.function.Function + +// kotlinc requires the anonymous inner class of this function to be on the classpath in order to +// inline this function. +inline fun appender(append: String): Function<String, String> { + return object : Function<String, String> { + override fun apply(arg: String) = arg + append + } +} + +// Additional regression test for https://youtrack.jetbrains.net/issue/KT-29471 +inline fun appender(crossinline init: () -> String): Function<String, String> { + return object : Function<String, String> { + private val base = init() + override fun apply(arg: String) = base + arg + } +} diff --git a/tests/jvm/java/ijar/InlineWhenMapping.kt b/tests/jvm/java/ijar/InlineWhenMapping.kt new file mode 100644 index 0000000..ba96d1d --- /dev/null +++ b/tests/jvm/java/ijar/InlineWhenMapping.kt @@ -0,0 +1,21 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ijar + +enum class MyEnum { A } + +inline fun <reified T> useWhenMapping(t: T, myE: MyEnum) = when (myE) { MyEnum.A -> t } diff --git a/tests/jvm/java/ijar/InlineWhenMappingUser.kt b/tests/jvm/java/ijar/InlineWhenMappingUser.kt new file mode 100644 index 0000000..1954039 --- /dev/null +++ b/tests/jvm/java/ijar/InlineWhenMappingUser.kt @@ -0,0 +1,21 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ijar + +fun main() { + println(useWhenMapping("OK", MyEnum.A)) +} diff --git a/tests/jvm/java/ijar/JvmStatics.kt b/tests/jvm/java/ijar/JvmStatics.kt new file mode 100644 index 0000000..deb14af --- /dev/null +++ b/tests/jvm/java/ijar/JvmStatics.kt @@ -0,0 +1,29 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ijar + +object JvmStatics { + + @JvmStatic + val something: String by lazy { "something" } + + // @JvmStatic annotation ends up on synthetic companion method we need to preserve + @JvmStatic + fun saySomething(): Unit { + println("${something}?") + } +} diff --git a/tests/jvm/java/ijar/Main.kt b/tests/jvm/java/ijar/Main.kt new file mode 100644 index 0000000..4457731 --- /dev/null +++ b/tests/jvm/java/ijar/Main.kt @@ -0,0 +1,25 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ijar + +fun main(args: Array<String>) { + JvmStatics.saySomething() + inlineMe<JvmStatics>() + println(appender("world").apply("hello ")) + println(appender { "world" }.apply(", hello!")) + println(inlineCapture("bye")) +} diff --git a/tests/jvm/java/ijar/ReifiedInline.kt b/tests/jvm/java/ijar/ReifiedInline.kt new file mode 100644 index 0000000..d22d90f --- /dev/null +++ b/tests/jvm/java/ijar/ReifiedInline.kt @@ -0,0 +1,21 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ijar + +// Need this method's content to inline it successfully. +// The reified type parameter causes this to be compiled to a private method. +inline fun <reified T : Any> inlineMe() = println("inline ${T::class}!") diff --git a/tests/jvm/java/ijar/SamExt.kt b/tests/jvm/java/ijar/SamExt.kt new file mode 100644 index 0000000..b0a4f42 --- /dev/null +++ b/tests/jvm/java/ijar/SamExt.kt @@ -0,0 +1,20 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ijar + +inline fun <T, R> SamInJava<T>.map(crossinline transform: (T) -> R): SamInJava<R> = + fmap { SamInJava(transform(it)) } diff --git a/tests/jvm/java/ijar/SamExtUser.kt b/tests/jvm/java/ijar/SamExtUser.kt new file mode 100644 index 0000000..603c4a2 --- /dev/null +++ b/tests/jvm/java/ijar/SamExtUser.kt @@ -0,0 +1,21 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ijar + +fun main() { + println(SamInJava("OK").map { it }) +} diff --git a/tests/jvm/java/ijar/SamInJava.java b/tests/jvm/java/ijar/SamInJava.java new file mode 100644 index 0000000..6589224 --- /dev/null +++ b/tests/jvm/java/ijar/SamInJava.java @@ -0,0 +1,35 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ijar; + +public class SamInJava<T> { + public final <R> SamInJava<R> fmap( + Function<? super T, ? extends SamInJava<? extends R>> mapper) { + return new SamInJava<R>(mapper.run(value).value); + } + + public SamInJava(T x) { + this.value = x; + } + + public final T value; + + @FunctionalInterface + public interface Function<T, R> { + R run(T arg); + } +} diff --git a/tests/jvm/java/ijar/SuspendTest.kt b/tests/jvm/java/ijar/SuspendTest.kt new file mode 100644 index 0000000..c4f9721 --- /dev/null +++ b/tests/jvm/java/ijar/SuspendTest.kt @@ -0,0 +1,46 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ijar + +import com.google.common.truth.Truth.assertThat +import kotlin.coroutines.Continuation +import kotlin.coroutines.EmptyCoroutineContext +import kotlin.coroutines.createCoroutine +import kotlin.coroutines.startCoroutine +import kotlin.coroutines.resume +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +/** Tests exercising suspend functions. */ +@RunWith(JUnit4::class) +class SuspendTest { + + /** Regression test for b/143465893. */ + @Test + fun testSuspendDoubleInline() { + suspend fun doubleInlineExample(): String { + return doubleInline("b") { "a" } + } + + // Run doubleInlineExample avoiding dependency on kotlinx.coroutines + var result: Result<String>? = null + ::doubleInlineExample.startCoroutine(Continuation(EmptyCoroutineContext, { r -> result = r })) + + assertThat(result!!.getOrThrow()).isEqualTo("ab") + } +} diff --git a/tests/jvm/java/internal/BUILD b/tests/jvm/java/internal/BUILD new file mode 100644 index 0000000..7bf2d8e --- /dev/null +++ b/tests/jvm/java/internal/BUILD @@ -0,0 +1,49 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//kotlin:rules.bzl", "kt_jvm_library", "kt_jvm_test") + +licenses(["notice"]) + +kt_jvm_library( + name = "internal", + srcs = ["Internal.kt"], +) + +kt_jvm_test( + name = "InternalTest", + srcs = ["InternalTest.kt"], + deps = [ + ":internal", + "@maven//:com_google_truth_truth", + "@maven//:junit_junit", + ], +) + +kt_jvm_library( + name = "internal_test_separate", + testonly = 1, + srcs = ["InternalTest.kt"], + deps = [ + ":internal", + "@maven//:com_google_truth_truth", + "@maven//:junit_junit", + ], +) + +java_test( + name = "InternalTest_separate", + test_class = "internal.InternalTest", + runtime_deps = [":internal_test_separate"], +) diff --git a/tests/jvm/java/internal/Internal.kt b/tests/jvm/java/internal/Internal.kt new file mode 100644 index 0000000..64f345b --- /dev/null +++ b/tests/jvm/java/internal/Internal.kt @@ -0,0 +1,25 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package internal + +class InternalClass { + internal val value = "Hello World" + internal fun hello() = "Hello friend" + suspend internal fun helloDelayed() = "Hello friend" +} + +internal fun internalFun(): String = "Hello World" diff --git a/tests/jvm/java/internal/InternalTest.kt b/tests/jvm/java/internal/InternalTest.kt new file mode 100644 index 0000000..aa9994f --- /dev/null +++ b/tests/jvm/java/internal/InternalTest.kt @@ -0,0 +1,42 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package internal + +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(JUnit4::class) +class InternalTest { + @Test + fun testInternalClassFieldVisible() { + val internalClass = InternalClass() + assertThat(internalClass.value).isEqualTo("Hello World") + } + + @Test + fun testInternalClassMethodVisible() { + val internalClass = InternalClass() + assertThat(internalClass.hello()).isEqualTo("Hello friend") + } + + @Test + fun testInternalFunVisible() { + assertThat(internalFun()).isEqualTo("Hello World") + } +} diff --git a/tests/jvm/java/jni/BUILD b/tests/jvm/java/jni/BUILD new file mode 100644 index 0000000..7225ef1 --- /dev/null +++ b/tests/jvm/java/jni/BUILD @@ -0,0 +1,92 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load( + "//kotlin:rules.bzl", + "kt_jvm_library", + "kt_jvm_test", +) + +package(default_testonly = 1) + +licenses(["notice"]) + +kt_jvm_library( + name = "NativeApiKt", + srcs = ["NativeApi.kt"], + visibility = ["//tests:__subpackages__"], + runtime_deps = [":jni_NativeApi"], +) + +java_library( + name = "NativeApiJava", + srcs = ["NativeApi.java"], + deps = [":libNativeApi.so"], +) + +java_library( + name = "NativeApiJava-through_cc_lib", + srcs = ["NativeApi.java"], + deps = [":native_api_so"], +) + +kt_jvm_library( + name = "NativeApiKt-through_cc_lib", + srcs = ["NativeApi.kt"], + runtime_deps = [":native_api_so"], +) + +cc_library( + name = "native_api_so", + srcs = [":libNativeApi.so"], +) + +cc_binary( + name = "libNativeApi.so", + linkshared = 1, + linkstatic = 1, + deps = [":jni_NativeApi"], +) + +cc_library( + name = "jni_NativeApi", + srcs = ["jni_NativeApi.cc"], + hdrs = ["jni_NativeApi.h"], # manually generated with "javac -h NativeApi.java" + deps = ["@bazel_tools//tools/jdk:jni"], + alwayslink = 1, +) + +[ + kt_jvm_test( + name = "NativeApiTest_" + native_loader, + srcs = ["NativeApiTest.kt"], + args = args, + main_class = "jni.NativeApiTestKt", + deps = [ + native_loader, + "@maven//:com_google_truth_truth", + "@maven//:junit_junit", + ], + ) + for native_loader, args in { + "NativeApiJava": ["--load"], + "NativeApiJava-through_cc_lib": ["--load"], + "NativeApiKt-through_cc_lib": ["--load"], + }.items() +] + +sh_test( + name = "jdk_check", + srcs = ["jdk_check.sh"], +) diff --git a/tests/jvm/java/jni/NativeApi.java b/tests/jvm/java/jni/NativeApi.java new file mode 100644 index 0000000..79d3949 --- /dev/null +++ b/tests/jvm/java/jni/NativeApi.java @@ -0,0 +1,27 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jni; + +/** + * Java equivalent of {@code NativeApi.kt} to generate a .h file using javac -h. Do not compile this + * file and the Kotlin equivalent into the same binary, they would conflict. + */ +public class NativeApi { + public static native String hello(String name); + + private NativeApi() {} +} diff --git a/tests/jvm/java/jni/NativeApi.kt b/tests/jvm/java/jni/NativeApi.kt new file mode 100644 index 0000000..987ec04 --- /dev/null +++ b/tests/jvm/java/jni/NativeApi.kt @@ -0,0 +1,24 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// @file:JvmName("NativeApi") + +package jni + +object NativeApi { + @JvmStatic + external fun hello(name: String): String +} diff --git a/tests/jvm/java/jni/NativeApiTest.kt b/tests/jvm/java/jni/NativeApiTest.kt new file mode 100644 index 0000000..f33b379 --- /dev/null +++ b/tests/jvm/java/jni/NativeApiTest.kt @@ -0,0 +1,31 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jni + +import com.google.common.truth.Truth.assertThat + +/** Unit test for JNI function. */ +fun main(args: Array<String>) { + if (args.getOrNull(0) == "--load") { + System.loadLibrary("NativeApi") // loads libNativeApi.so + } + + assertThat(NativeApi.hello("World")).isEqualTo("Hello, World") + + assertThat(NativeApi.hello("0123456789".repeat(11) + "willbedropped")) + .isEqualTo("Hello, " + "0123456789".repeat(11) + "willbedrop") +} diff --git a/tests/jvm/java/jni/jdk_check.sh b/tests/jvm/java/jni/jdk_check.sh new file mode 100755 index 0000000..b741899 --- /dev/null +++ b/tests/jvm/java/jni/jdk_check.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +if [[ $(type java) =~ /usr/local/buildtools/java/jdk/bin/java ]]; then + echo "Unexpected google JDK" + exit 1 +fi diff --git a/tests/jvm/java/jni/jni_NativeApi.cc b/tests/jvm/java/jni/jni_NativeApi.cc new file mode 100644 index 0000000..a0359ac --- /dev/null +++ b/tests/jvm/java/jni/jni_NativeApi.cc @@ -0,0 +1,26 @@ +// Copyright 2022 Google LLC. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "jni_NativeApi.h" +#include <string.h> + +JNIEXPORT jstring JNICALL Java_jni_NativeApi_hello + (JNIEnv *env, jclass clazz, jstring name) { + const char* str = env->GetStringUTFChars(name, 0); + char cap[128]; // simplified since this is demo code + strcpy(cap, "Hello, "); + strncpy(cap + 7, str, 120); + env->ReleaseStringUTFChars(name, str); + return env->NewStringUTF(cap); +} diff --git a/tests/jvm/java/jni/jni_NativeApi.h b/tests/jvm/java/jni/jni_NativeApi.h new file mode 100644 index 0000000..a18afb9 --- /dev/null +++ b/tests/jvm/java/jni/jni_NativeApi.h @@ -0,0 +1,35 @@ +// Copyright 2022 Google LLC. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class jni_NativeApi */ + +#ifndef _Included_jni_NativeApi +#define _Included_jni_NativeApi +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: jni_NativeApi + * Method: hello + * Signature: (Ljava/lang/String;)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_jni_NativeApi_hello + (JNIEnv *, jclass, jstring); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tests/jvm/java/junit/BUILD b/tests/jvm/java/junit/BUILD new file mode 100644 index 0000000..af26b52 --- /dev/null +++ b/tests/jvm/java/junit/BUILD @@ -0,0 +1,59 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//kotlin:rules.bzl", "kt_jvm_library", "kt_jvm_test") + +package(default_testonly = 1) + +licenses(["notice"]) + +kt_jvm_library( + name = "junit", + srcs = glob(["*.kt"]), + deps = [ + "@maven//:com_google_truth_truth", + "@maven//:junit_junit", + ], +) + +# test_class inferred from test name (srcs irrelevant) +kt_jvm_test( + name = "FooTest", + srcs = ["FooTest.kt"], + tags = ["darwin_x86_64_compatible"], + deps = [ + "@maven//:com_google_truth_truth", + "@maven//:junit_junit", + ], +) + +kt_jvm_test( + name = "FooTest_separate", + tags = ["darwin_x86_64_compatible"], + test_class = "junit.FooTest", + runtime_deps = [":junit"], +) + +# test_class inferred from test name (srcs not needed) +kt_jvm_test( + name = "BarTest", + tags = ["darwin_x86_64_compatible"], + runtime_deps = [":junit"], +) + +java_test( + name = "SampleTest", + tags = ["darwin_x86_64_compatible"], + runtime_deps = [":junit"], +) diff --git a/tests/jvm/java/junit/BarTest.kt b/tests/jvm/java/junit/BarTest.kt new file mode 100644 index 0000000..ceab8cc --- /dev/null +++ b/tests/jvm/java/junit/BarTest.kt @@ -0,0 +1,31 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package junit + +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(JUnit4::class) +class BarTest { + + @Test + fun testSomething() { + assertThat(false).isFalse() + } +} diff --git a/tests/jvm/java/junit/FooTest.kt b/tests/jvm/java/junit/FooTest.kt new file mode 100644 index 0000000..78ddfea --- /dev/null +++ b/tests/jvm/java/junit/FooTest.kt @@ -0,0 +1,31 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package junit + +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(JUnit4::class) +class FooTest { + + @Test + fun testSomething() { + assertThat(true).isTrue() + } +} diff --git a/tests/jvm/java/junit/SampleTest.kt b/tests/jvm/java/junit/SampleTest.kt new file mode 100644 index 0000000..24b6917 --- /dev/null +++ b/tests/jvm/java/junit/SampleTest.kt @@ -0,0 +1,35 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package junit + +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(JUnit4::class) +public class SampleTest { + @Test + public fun tru() { + assertThat(true).isTrue() + } + + @Test + public fun fls() { + assertThat(false).isFalse() + } +} diff --git a/tests/jvm/java/kapt/AP.java b/tests/jvm/java/kapt/AP.java new file mode 100644 index 0000000..984a444 --- /dev/null +++ b/tests/jvm/java/kapt/AP.java @@ -0,0 +1,75 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.google.auto.service.AutoService; +import java.io.IOException; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.util.Set; +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + +/** Simple test processor that numbered classes in rounds as specified in {@link Count}. */ +@AutoService(Processor.class) +@SupportedAnnotationTypes("*") +public class AP extends AbstractProcessor { + + private volatile String prefix = ""; + + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + prefix = processingEnv.getOptions().getOrDefault("kapt.AP.indexPrefix", ""); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + @Override + public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { + for (Element element : roundEnv.getElementsAnnotatedWith(Count.class)) { + Count c = element.getAnnotation(Count.class); + if (c.value() > 0) { + int next = c.value() - 1; + String simpleName = element.getSimpleName() + "_" + prefix + next; + try (OutputStream os = + processingEnv + .getFiler() + .createSourceFile("kapt." + simpleName, element) + .openOutputStream()) { + os.write( + String.format("package kapt; @Count(%d) class %s {}", next, simpleName) + .getBytes(UTF_8)); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + } + return false; + } +} diff --git a/tests/jvm/java/kapt/APTest.kt b/tests/jvm/java/kapt/APTest.kt new file mode 100644 index 0000000..cd1dfa6 --- /dev/null +++ b/tests/jvm/java/kapt/APTest.kt @@ -0,0 +1,60 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt + +import com.google.testing.compile.Compilation +import com.google.testing.compile.CompilationSubject.assertThat +import com.google.testing.compile.Compiler.javac +import com.google.testing.compile.JavaFileObjects +import javax.tools.JavaFileObject +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +/** Sample test for [AP] that uses `com.google.testing.compile` (b/199411692). */ +@RunWith(JUnit4::class) +class APTest { + @Test + fun testKTest() { + // This is the stub file kapt generates for KTest.kt as of kotlinc 1.5.31, with the original + // Kotlin module name shortened. + // Alternatively our test could run kapt to get a fresh stub file, but on the other hand we + // can test with a particular stub file this way, which may be useful for some regression tests. + val testStub = JavaFileObjects.forSourceString( + /* fullyQualifiedName= */ "kapt.KTest", + """ + |package kapt; + + |import java.lang.System; + + |@kotlin.Metadata(mv = {1, 5, 1}, k = 1, d1 = {"\u0000\f\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\b\u0007\u0018\u00002\u00020\u0001B\u0005\u00a2\u0006\u0002\u0010\u0002\u00a8\u0006\u0003"}, d2 = {"Lkapt/KTest;", "", "()V", "shortened.java.kapt_test_kapt"}) + |@Count(value = 3, clazz = KTest_2_1_0.class) + |public final class KTest { + | + | public KTest() { + | super(); + | } + |} + """.trimMargin() + ) + val compilation: Compilation = javac().withProcessors(AP()).compile(testStub) + assertThat(compilation).succeededWithoutWarnings() + assertThat(compilation).generatedSourceFile("kapt.KTest_2") + assertThat(compilation).generatedSourceFile("kapt.KTest_2_1") + assertThat(compilation).generatedSourceFile("kapt.KTest_2_1_0") + } +} diff --git a/tests/jvm/java/kapt/BUILD b/tests/jvm/java/kapt/BUILD new file mode 100644 index 0000000..43b893d --- /dev/null +++ b/tests/jvm/java/kapt/BUILD @@ -0,0 +1,313 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load( + "//kotlin:rules.bzl", + "kt_jvm_library", + "kt_jvm_test", +) +load("@bazel_skylib//rules:build_test.bzl", "build_test") + +licenses(["notice"]) + +build_test( + name = "kapt_regressions", + tags = ["darwin_x86_64_compatible"], + targets = [ + ":test_javac", + ":test_kapt", + ":test_javac", + ":test_javac_with_exported_plugin", + ":test_kapt_with_exported_plugin", + ":test_no_processors", + ":test_noop", + ":test_noop_processors_ignored", + ":test_processor_flags", + ":test_processor_with_data", + ":test_reference", + ":test_stubs", + ":test_direct_classpath", + ], +) + +# Regression test for no processor outputs (b/79878966) +# and running non-service processors (b/110540324) +kt_jvm_library( + name = "test_noop", + srcs = ["Noop.kt"], + plugins = [ + ":non_service_processor", + ], +) + +kt_jvm_library( + name = "test_kapt", + srcs = [ + "KTest.kt", + ], + plugins = [":AP"], + deps = [ + ":anno", + ], +) + +# Test support for -A processor flags (b/134963914). +kt_jvm_library( + name = "test_processor_flags", + srcs = ["FlagTest.kt"], + javacopts = ["-Akapt.AP.indexPrefix=Gen"], + plugins = [":AP"], + deps = [":anno"], +) + +# Skip kapt altogether when no plugin defines a processor (b/110540324). +kt_jvm_library( + name = "test_no_processors", + srcs = [ + "Noop.kt", + ], + plugins = [ + ":ignored_failing_processor", # would fail if run + ], + deps = [ + ":anno", + ], +) + +# Skip plugins without processors, for consistency with how Blaze runs javac (b/110540324). +kt_jvm_library( + name = "test_noop_processors_ignored", + srcs = [ + "KTest.kt", + ], + plugins = [ + ":AP", + ":ignored_failing_processor", # would fail if run + ], + deps = [ + ":anno", + ], +) + +# Use kapt to annotation-process a .java file +kt_jvm_library( + name = "test_kapt_java", + srcs = [ + "Noop.kt", # needed so kapt is used + "Test.java", + ], + plugins = [":AP"], + deps = [ + ":anno", + ], +) + +# No .kt sources: javac is used for annotation processing +kt_jvm_library( + name = "test_javac", + srcs = ["Test.java"], + plugins = [":AP"], + deps = [ + ":anno", + ], +) + +# Test for java_library picking up exported_plugin from kt_jvm_library +java_library( + name = "test_javac_with_exported_plugin", + srcs = ["Test.java"], + deps = [ + ":anno_with_plugin", + ], +) + +# Reference build with java_library +java_library( + name = "test_reference", + srcs = ["Test.java"], + plugins = [":AP"], + deps = [ + ":anno", + ], +) + +# This target compiles repro code for b/118338417 and b/110373008. Since these are issues with the +# kapt-generated .java stub files, which aren't currently used by the Kotlin build rules, this +# target compiles, but we can manually inspect the stubs to see if issues were fixed. +# TODO: Turn this into a dump test asserting the content of the generated stubs +kt_jvm_library( + name = "test_stubs", + srcs = [ + "InnerEnumImport.kt", # repro for https://youtrack.jetbrains.net/issue/KT-28220 + "SealedClasses.kt", # repro for https://youtrack.jetbrains.net/issue/KT-29924 + "StaticImport.kt", # Static* repro https://youtrack.jetbrains.net/issue/KT-25071 (fixed) + "StaticMethod.java", + ], + plugins = [":AP"], +) + +java_plugin( + name = "AP", + generates_api = 1, + processor_class = "kapt.AP", + deps = [":AP_lib"], +) + +java_library( + name = "AP_lib", + srcs = ["AP.java"], + deps = [ + ":anno", + "//bazel:auto_service", + ], +) + +# Processor that doesn't advertise itself to j.u.ServiceLoader (regression for b/110540324) +java_plugin( + name = "non_service_processor", + srcs = ["NonServiceProcessor.java"], + processor_class = "kapt.NonServiceProcessor", +) + +# Processor that would fail but doesn't declare processor_class and hence shouldn't run. +java_plugin( + name = "ignored_failing_processor", + srcs = ["FailingProcessor.java"], + deps = [ + "//bazel:auto_service", + ], +) + +java_library( + name = "anno", + srcs = ["Count.java"], +) + +kt_jvm_library( + name = "anno_with_plugin", + srcs = ["Count.java"], + exported_plugins = [":AP"], +) + +kt_jvm_library( + name = "test_kapt_with_exported_plugin", + srcs = ["KTest.kt"], + deps = [ + ":anno_with_plugin", + ], +) + +# Regression test for b/199932860: processor with data dependency +java_plugin( + name = "ProcessorWithData", + data = ["MakeHelperClass.java.template"], + processor_class = "kapt.ProcessorWithData", + deps = [":processor_with_data"], +) + +kt_jvm_library( + name = "processor_with_data", + srcs = [ + "MakeHelper.kt", + "ProcessorWithData.kt", + ], + deps = [ + "//bazel:auto_service", + ], +) + +kt_jvm_library( + name = "make_helper", + srcs = ["MakeHelper.kt"], + exported_plugins = [":ProcessorWithData"], +) + +kt_jvm_library( + name = "test_processor_with_data", + srcs = ["TriggerHelper.kt"], + deps = [":make_helper"], +) + +kt_jvm_library( + name = "generates_services", + srcs = ["GeneratesServices.kt"], + deps = [ + "//bazel:auto_service", + ], +) + +kt_jvm_test( + name = "GeneratesServicesTest", + srcs = ["GeneratesServicesTest.kt"], + tags = ["darwin_x86_64_compatible"], + deps = [ + ":generates_services", + "@maven//:com_google_truth_truth", + "@maven//:junit_junit", + ], +) + +kt_jvm_library( + name = "dagger_c", + testonly = 1, + srcs = ["DaggerC.kt"], + deps = [ + "@maven//:javax_inject_jsr330_api", + ], +) + +kt_jvm_library( + name = "dagger_b", + testonly = 1, + srcs = ["DaggerB.kt"], + deps = [ + ":dagger_c", + "@maven//:javax_inject_jsr330_api", + ], +) + +kt_jvm_library( + name = "dagger_a", + testonly = 1, + srcs = ["DaggerA.kt"], + deps = [ + ":dagger_b", + ":dagger_c", + "@dagger", + ], +) + +# Tests a scenario where Dagger generates code referencing indirect dependencies, which can confuse +# Blaze's direct classpath optimization for running Turbine. +kt_jvm_library( + name = "test_direct_classpath", + testonly = 1, + srcs = ["DaggerTopLevel.kt"], + deps = [ + ":dagger_a", + ], +) + +# Demonstrates a simple compile test that uses Kotlin kapt stubs (b/199411692) +kt_jvm_test( + name = "APTest", + srcs = ["APTest.kt"], + tags = ["darwin_x86_64_compatible"], + deps = [ + ":AP_lib", + "@maven//:com_google_testing_compile_compile_testing", + "@maven//:com_google_truth_truth", + "@maven//:junit_junit", + ], +) diff --git a/tests/jvm/java/kapt/Count.java b/tests/jvm/java/kapt/Count.java new file mode 100644 index 0000000..17332db --- /dev/null +++ b/tests/jvm/java/kapt/Count.java @@ -0,0 +1,23 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt; + +/** Annotation used by {@link AP}. */ +public @interface Count { + int value() default 0; + Class<?> clazz() default Object.class; +} diff --git a/tests/jvm/java/kapt/DaggerA.kt b/tests/jvm/java/kapt/DaggerA.kt new file mode 100644 index 0000000..ee319bd --- /dev/null +++ b/tests/jvm/java/kapt/DaggerA.kt @@ -0,0 +1,32 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt + +import dagger.Component +import javax.inject.Singleton + +class DaggerA { + @Singleton + @Component + public interface Thing { + fun b(): DaggerB + } + + fun main() { + DaggerDaggerA_Thing.builder().build().b() + } +} diff --git a/tests/jvm/java/kapt/DaggerB.kt b/tests/jvm/java/kapt/DaggerB.kt new file mode 100644 index 0000000..f487b8a --- /dev/null +++ b/tests/jvm/java/kapt/DaggerB.kt @@ -0,0 +1,21 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt + +import javax.inject.Inject + +public class DaggerB @Inject public constructor(c: DaggerC) {} diff --git a/tests/jvm/java/kapt/DaggerC.kt b/tests/jvm/java/kapt/DaggerC.kt new file mode 100644 index 0000000..6a9dd3d --- /dev/null +++ b/tests/jvm/java/kapt/DaggerC.kt @@ -0,0 +1,22 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt + +import javax.inject.Inject + +public class DaggerC @Inject public constructor() {} + diff --git a/tests/jvm/java/kapt/DaggerTopLevel.kt b/tests/jvm/java/kapt/DaggerTopLevel.kt new file mode 100644 index 0000000..27adb00 --- /dev/null +++ b/tests/jvm/java/kapt/DaggerTopLevel.kt @@ -0,0 +1,23 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt + +class DaggerTopLevel { + fun main() { + DaggerA().main() + } +} diff --git a/tests/jvm/java/kapt/FailingProcessor.java b/tests/jvm/java/kapt/FailingProcessor.java new file mode 100644 index 0000000..1e3e703 --- /dev/null +++ b/tests/jvm/java/kapt/FailingProcessor.java @@ -0,0 +1,49 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt; + + +import com.google.auto.service.AutoService; +import java.util.Set; +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.TypeElement; + +/** Annotation processor that fails when invoked. */ +@AutoService(Processor.class) +@SupportedAnnotationTypes("*") +public class FailingProcessor extends AbstractProcessor { + + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + @Override + public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { + throw new IllegalStateException("Shouldn't get here"); + } +} diff --git a/tests/jvm/java/kapt/FlagTest.kt b/tests/jvm/java/kapt/FlagTest.kt new file mode 100644 index 0000000..acf6145 --- /dev/null +++ b/tests/jvm/java/kapt/FlagTest.kt @@ -0,0 +1,22 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt + +/** Requires -Akapt.AP.indexPrefix=Gen to generate expected class name. */ +@Count(value = 3, clazz = FlagTest_Gen2_Gen1_Gen0::class) +class FlagTest { +} diff --git a/tests/jvm/java/kapt/GeneratesServices.kt b/tests/jvm/java/kapt/GeneratesServices.kt new file mode 100644 index 0000000..771743d --- /dev/null +++ b/tests/jvm/java/kapt/GeneratesServices.kt @@ -0,0 +1,28 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt + +import com.google.auto.service.AutoService + +public interface Regressible { + val regressed: Boolean +} + +@AutoService(Regressible::class) +public class Fixed() : Regressible { + override val regressed = false +} diff --git a/tests/jvm/java/kapt/GeneratesServicesTest.kt b/tests/jvm/java/kapt/GeneratesServicesTest.kt new file mode 100644 index 0000000..c2b4c56 --- /dev/null +++ b/tests/jvm/java/kapt/GeneratesServicesTest.kt @@ -0,0 +1,35 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt + +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +import java.util.ServiceLoader + +@RunWith(JUnit4::class) +class GeneratesServicesTest { + + @Test + fun servicesDiscoverable() { + val impls = ServiceLoader.load(Regressible::class.java) + assertThat(impls).isNotEmpty() + assertThat(impls.iterator().next().regressed).isFalse() + } +} diff --git a/tests/jvm/java/kapt/InnerEnumImport.kt b/tests/jvm/java/kapt/InnerEnumImport.kt new file mode 100644 index 0000000..ef4b4f1 --- /dev/null +++ b/tests/jvm/java/kapt/InnerEnumImport.kt @@ -0,0 +1,36 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt + +import kapt.InnerEnumImport.Options.A +import kapt.InnerEnumImport.Options.B +import kapt.InnerEnumImport.Options.C + +class InnerEnumImport { + fun name(o: Options) = + when (o) { + A -> "a" + B -> "b" + C -> "c" + } + + enum class Options { + A, + B, + C + } +} diff --git a/tests/jvm/java/kapt/InterfaceWithDefaultImpls.kt b/tests/jvm/java/kapt/InterfaceWithDefaultImpls.kt new file mode 100644 index 0000000..a9aad4f --- /dev/null +++ b/tests/jvm/java/kapt/InterfaceWithDefaultImpls.kt @@ -0,0 +1,25 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This file contains the example filed upstream for b/121222399. +// TODO: Turn this into a regression test once the issue is fixed. +package kapt + +interface Base<T> + +interface HasDefaultMethod<T> : Base<T> { + fun print(msg: String) = println(msg) +} diff --git a/tests/jvm/java/kapt/KTest.kt b/tests/jvm/java/kapt/KTest.kt new file mode 100644 index 0000000..88efba8 --- /dev/null +++ b/tests/jvm/java/kapt/KTest.kt @@ -0,0 +1,21 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt + +@Count(value = 3, clazz = KTest_2_1_0::class) +class KTest { +} diff --git a/tests/jvm/java/kapt/MakeHelper.kt b/tests/jvm/java/kapt/MakeHelper.kt new file mode 100644 index 0000000..9809f34 --- /dev/null +++ b/tests/jvm/java/kapt/MakeHelper.kt @@ -0,0 +1,22 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt + +import kotlin.reflect.KClass + +/** Annotation to specify a file name for `ProcessorWithData`. */ +annotation class MakeHelper(val value: String) diff --git a/tests/jvm/java/kapt/MakeHelperClass.java.template b/tests/jvm/java/kapt/MakeHelperClass.java.template new file mode 100644 index 0000000..db25fc7 --- /dev/null +++ b/tests/jvm/java/kapt/MakeHelperClass.java.template @@ -0,0 +1,20 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt; + +/** Java class copied into output by {@code ProcessorWithData}. */ +class |name| {} diff --git a/tests/jvm/java/kapt/NonServiceProcessor.java b/tests/jvm/java/kapt/NonServiceProcessor.java new file mode 100644 index 0000000..cab01d9 --- /dev/null +++ b/tests/jvm/java/kapt/NonServiceProcessor.java @@ -0,0 +1,45 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt; + +import java.util.Set; +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.TypeElement; + +/** Annotation processor <b>not</b> loadable via service loader. */ +@SupportedAnnotationTypes("*") +public class NonServiceProcessor extends AbstractProcessor { + + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + @Override + public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { + return false; + } +} diff --git a/tests/jvm/java/kapt/Noop.kt b/tests/jvm/java/kapt/Noop.kt new file mode 100644 index 0000000..0c3d9c3 --- /dev/null +++ b/tests/jvm/java/kapt/Noop.kt @@ -0,0 +1,20 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt + +fun main(argv : Array<String>) { +} diff --git a/tests/jvm/java/kapt/ProcessorWithData.kt b/tests/jvm/java/kapt/ProcessorWithData.kt new file mode 100644 index 0000000..0d58205 --- /dev/null +++ b/tests/jvm/java/kapt/ProcessorWithData.kt @@ -0,0 +1,65 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt + +import com.google.auto.service.AutoService +import java.io.IOException +import java.io.UncheckedIOException +import java.nio.charset.StandardCharsets.UTF_8 +import java.nio.file.Files +import java.nio.file.Paths +import javax.annotation.processing.AbstractProcessor +import javax.annotation.processing.Processor +import javax.annotation.processing.RoundEnvironment +import javax.annotation.processing.SupportedAnnotationTypes +import javax.lang.model.SourceVersion +import javax.lang.model.element.TypeElement + +/** Annotation processor to test `data` dependencies specified with [MakeHelper] annotations. */ +@AutoService(Processor::class) +@SupportedAnnotationTypes("*") +internal class ProcessorWithData : AbstractProcessor() { + + private val template: String = + Files.readString( + Paths.get( + "tests/jvm/java/kapt/MakeHelperClass.java.template" + ), + UTF_8 + ) + + override fun getSupportedSourceVersion(): SourceVersion = SourceVersion.latestSupported() + + override fun process( + annotations: Set<TypeElement>, + roundEnv: RoundEnvironment, + ): Boolean { + for (element in roundEnv.getElementsAnnotatedWith(MakeHelper::class.java)) { + val c = element.getAnnotation(MakeHelper::class.java) + if (c.value.isNotEmpty()) { + try { + processingEnv.filer.createSourceFile(c.value, element).openWriter().use { + it.write(template.replace("|name|", c.value.substring(c.value.lastIndexOf(".") + 1))) + } + } catch (e: IOException) { + throw UncheckedIOException(e) + } + } + } + return false + } +} diff --git a/tests/jvm/java/kapt/SealedClasses.kt b/tests/jvm/java/kapt/SealedClasses.kt new file mode 100644 index 0000000..7727e08 --- /dev/null +++ b/tests/jvm/java/kapt/SealedClasses.kt @@ -0,0 +1,21 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt + +sealed class Sealed + +class Sub : Sealed() diff --git a/tests/jvm/java/kapt/StaticImport.kt b/tests/jvm/java/kapt/StaticImport.kt new file mode 100644 index 0000000..28d3752 --- /dev/null +++ b/tests/jvm/java/kapt/StaticImport.kt @@ -0,0 +1,25 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt + +import java.util.Objects.isNull +import kapt.StaticMethod.of + +class StaticImport { + val x = isNull("hello") + val list = of("hello", "world") +} diff --git a/tests/jvm/java/kapt/StaticMethod.java b/tests/jvm/java/kapt/StaticMethod.java new file mode 100644 index 0000000..5c6fc0c --- /dev/null +++ b/tests/jvm/java/kapt/StaticMethod.java @@ -0,0 +1,32 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt; + +public class StaticMethod<T> { + public static <T> StaticMethod<T> of(T t1) { + return new StaticMethod<T>(t1); + } + public static <T> StaticMethod<T> of(T t1, T t2) { + return new StaticMethod<T>(t1, t2); + } + + private final T[] ts; + + private StaticMethod(T... ts) { + this.ts = ts; + } +} diff --git a/tests/jvm/java/kapt/Test.java b/tests/jvm/java/kapt/Test.java new file mode 100644 index 0000000..f3ca1cf --- /dev/null +++ b/tests/jvm/java/kapt/Test.java @@ -0,0 +1,22 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt; + +@Count(value = 3, clazz = Test_2_1_0.class) +class Test { + Test_2_1_0 x; +} diff --git a/tests/jvm/java/kapt/TriggerHelper.kt b/tests/jvm/java/kapt/TriggerHelper.kt new file mode 100644 index 0000000..0ccb204 --- /dev/null +++ b/tests/jvm/java/kapt/TriggerHelper.kt @@ -0,0 +1,24 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kapt + +/** Cause `ProcessorWithData` to generate a class with the specified name. */ +@MakeHelper("kapt.GeneratedHelper") +class TriggerHelper { + /** Property that makes sure the file is successfully copied and compiled into this package. */ + private val helper = GeneratedHelper() +} diff --git a/tests/jvm/java/metasyntactic/BUILD b/tests/jvm/java/metasyntactic/BUILD new file mode 100644 index 0000000..6ee26a9 --- /dev/null +++ b/tests/jvm/java/metasyntactic/BUILD @@ -0,0 +1,60 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//kotlin:rules.bzl", "kt_jvm_library", "kt_jvm_test") + +licenses(["notice"]) + +kt_jvm_library( + name = "Bar", + srcs = ["Bar.kt"], +) + +kt_jvm_library( + name = "FooBar", + srcs = ["FooBar.java"], + deps = [":Bar"], +) + +java_library( + name = "Qux", + srcs = ["Qux.java"], +) + +kt_jvm_library( + name = "BazQux", + srcs = ["BazQux.kt"], + deps = [":Qux"], +) + +kt_jvm_library( + name = "QuuxCorgeGrault", + srcs = [ + "Corge.java", + "QuuxCorge.kt", + "QuuxCorgeGrault.java", + ], +) + +kt_jvm_test( + name = "Main", + srcs = ["Main.kt"], + main_class = "metasyntactic.Main", + tags = ["darwin_x86_64_compatible"], + deps = [ + ":BazQux", + ":FooBar", + ":QuuxCorgeGrault", + ], +) diff --git a/tests/jvm/java/metasyntactic/Bar.kt b/tests/jvm/java/metasyntactic/Bar.kt new file mode 100644 index 0000000..f39c411 --- /dev/null +++ b/tests/jvm/java/metasyntactic/Bar.kt @@ -0,0 +1,21 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:JvmName("Bar") + +package metasyntactic + +fun bar(): String = "Bar" diff --git a/tests/jvm/java/metasyntactic/BazQux.kt b/tests/jvm/java/metasyntactic/BazQux.kt new file mode 100644 index 0000000..db6239f --- /dev/null +++ b/tests/jvm/java/metasyntactic/BazQux.kt @@ -0,0 +1,23 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:JvmName("BazQux") + +package metasyntactic + +fun baz(): String = "Baz" + +fun bazQux(): String = baz() + Qux.qux() diff --git a/tests/jvm/java/metasyntactic/Corge.java b/tests/jvm/java/metasyntactic/Corge.java new file mode 100644 index 0000000..10e5c36 --- /dev/null +++ b/tests/jvm/java/metasyntactic/Corge.java @@ -0,0 +1,25 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package metasyntactic; + +/** Corge */ +public class Corge { + + public static String corge() { + return "Corge"; + } +} diff --git a/tests/jvm/java/metasyntactic/FooBar.java b/tests/jvm/java/metasyntactic/FooBar.java new file mode 100644 index 0000000..743ebab --- /dev/null +++ b/tests/jvm/java/metasyntactic/FooBar.java @@ -0,0 +1,29 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package metasyntactic; + +/** FooBar */ +public class FooBar { + + public static String foo() { + return "Foo"; + } + + public static String fooBar() { + return foo() + Bar.bar(); + } +} diff --git a/tests/jvm/java/metasyntactic/Main.kt b/tests/jvm/java/metasyntactic/Main.kt new file mode 100644 index 0000000..559822b --- /dev/null +++ b/tests/jvm/java/metasyntactic/Main.kt @@ -0,0 +1,23 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:JvmName("Main") + +package metasyntactic + +fun main(args: Array<String>) { + println(FooBar.fooBar() + bazQux() + QuuxCorgeGrault.quuxCorgeGrault() + "!") +} diff --git a/tests/jvm/java/metasyntactic/QuuxCorge.kt b/tests/jvm/java/metasyntactic/QuuxCorge.kt new file mode 100644 index 0000000..ce84a83 --- /dev/null +++ b/tests/jvm/java/metasyntactic/QuuxCorge.kt @@ -0,0 +1,23 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:JvmName("QuuxCorge") + +package metasyntactic + +fun quux(): String = "Quux" + +fun quuxCorge(): String = quux() + Corge.corge() diff --git a/tests/jvm/java/metasyntactic/QuuxCorgeGrault.java b/tests/jvm/java/metasyntactic/QuuxCorgeGrault.java new file mode 100644 index 0000000..f7a9771 --- /dev/null +++ b/tests/jvm/java/metasyntactic/QuuxCorgeGrault.java @@ -0,0 +1,29 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package metasyntactic; + +/** QuuxCorgeGrault */ +public class QuuxCorgeGrault { + + public static String grault() { + return "Grault"; + } + + public static String quuxCorgeGrault() { + return QuuxCorge.quuxCorge() + grault(); + } +} diff --git a/tests/jvm/java/metasyntactic/Qux.java b/tests/jvm/java/metasyntactic/Qux.java new file mode 100644 index 0000000..5c5d231 --- /dev/null +++ b/tests/jvm/java/metasyntactic/Qux.java @@ -0,0 +1,25 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package metasyntactic; + +/** Qux */ +public class Qux { + + public static String qux() { + return "Qux"; + } +} diff --git a/tests/jvm/java/metasyntactic/Qux.kt b/tests/jvm/java/metasyntactic/Qux.kt new file mode 100644 index 0000000..20517b9 --- /dev/null +++ b/tests/jvm/java/metasyntactic/Qux.kt @@ -0,0 +1,21 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:JvmName("FooBar") + +package foo + +fun bar(): String = "FooBar!" diff --git a/tests/jvm/java/mockito/BUILD b/tests/jvm/java/mockito/BUILD new file mode 100644 index 0000000..ade78c9 --- /dev/null +++ b/tests/jvm/java/mockito/BUILD @@ -0,0 +1,29 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//kotlin:rules.bzl", "kt_jvm_test") + +package(default_testonly = 1) + +licenses(["notice"]) + +kt_jvm_test( + name = "MockitoTest", + srcs = glob(["*.kt"]), + deps = [ + "@maven//:com_google_truth_truth", + "@maven//:junit_junit", + "@maven//:org_mockito_mockito_core", + ], +) diff --git a/tests/jvm/java/mockito/MockitoTest.kt b/tests/jvm/java/mockito/MockitoTest.kt new file mode 100644 index 0000000..757f87d --- /dev/null +++ b/tests/jvm/java/mockito/MockitoTest.kt @@ -0,0 +1,39 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package mockito + +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.mockito.Mockito + +@RunWith(JUnit4::class) +class MockitoTest { + @Test + fun dummyTest() { + val mocked = Mockito.mock(WithExtensionMethod::class.java) + assertThat(mocked).isInstanceOf(WithExtensionMethod::class.java) + } +} + +interface WithExtensionMethod { + fun GenericClass<*>.doSomething() + fun String.doSomethingElse(arg: GenericClass<*>) +} + +open class GenericClass<T> diff --git a/tests/jvm/java/multijarimport/A.kt b/tests/jvm/java/multijarimport/A.kt new file mode 100644 index 0000000..7b7f942 --- /dev/null +++ b/tests/jvm/java/multijarimport/A.kt @@ -0,0 +1,20 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package multijarimport + +/** A test class. */ +class A(val msg: String) diff --git a/tests/jvm/java/multijarimport/B.kt b/tests/jvm/java/multijarimport/B.kt new file mode 100644 index 0000000..2505982 --- /dev/null +++ b/tests/jvm/java/multijarimport/B.kt @@ -0,0 +1,22 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package multijarimport + +/** A test class that needs A */ +class B { + fun use(a: A): String = a.msg +} diff --git a/tests/jvm/java/multijarimport/BUILD b/tests/jvm/java/multijarimport/BUILD new file mode 100644 index 0000000..d3e6057 --- /dev/null +++ b/tests/jvm/java/multijarimport/BUILD @@ -0,0 +1,65 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//kotlin:rules.bzl", "kt_jvm_import", "kt_jvm_library") + +package( + default_testonly = 1, +) + +licenses(["notice"]) + +# During coverage builds, every library gets a dep on JaCoCo (Java Code Coverage). +# Libjars, from libraries, only include their direct sources. Together, these behaviours +# trigger an ImportDepsChecker error for :import_a_and_b. To prevent that, we disable +# coverage builds on all downstream targets. +_NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO = ["nozapfhahn"] + +kt_jvm_library( + name = "A", + srcs = ["A.kt"], +) + +kt_jvm_library( + name = "B", + srcs = ["B.kt"], + deps = [":A"], +) + +# This import target with multiple JARs is the main thing we're testing. +kt_jvm_import( + name = "import_a_and_b", + jars = [ + ":libA.jar", + ":libB.jar", + ], + srcjar = ":libB-src.jar", + tags = _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO, +) + +kt_jvm_library( + name = "TestRunner", + srcs = ["TestRunner.kt"], + tags = _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO, + deps = [":import_a_and_b"], +) + +java_test( + name = "multijarimport_test", + main_class = "multijarimport.TestRunner", + tags = _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO, + runtime_deps = [ + ":TestRunner", + ], +) diff --git a/tests/jvm/java/multijarimport/TestRunner.kt b/tests/jvm/java/multijarimport/TestRunner.kt new file mode 100644 index 0000000..e290159 --- /dev/null +++ b/tests/jvm/java/multijarimport/TestRunner.kt @@ -0,0 +1,30 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package multijarimport + +object TestRunner { + + @JvmStatic + fun main(args: Array<String>) { + val a = A("hello") + val b = B() + + if (b.use(a) != "hello") { + throw AssertionError() + } + } +} diff --git a/tests/jvm/java/srcartifacts/BUILD b/tests/jvm/java/srcartifacts/BUILD new file mode 100644 index 0000000..4236672 --- /dev/null +++ b/tests/jvm/java/srcartifacts/BUILD @@ -0,0 +1,118 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//kotlin:rules.bzl", "kt_jvm_library", "kt_jvm_test") +load("//tests/analysis:util.bzl", "create_dir", "create_file") +load("@bazel_skylib//rules:build_test.bzl", "build_test") + +package(default_testonly = 1) + +licenses(["notice"]) + +kt_jvm_test( + name = "srcartifacts", + srcs = [ + "JavaSrc.java", + "KtSrc.kt", + "SrcArtifactsTest.kt", + ":JavaSrcjar_gen", + ":dir/java", + ":dir/kotlin", + ], + resources = [ + "dir/empty", + "dir/resources", + ], + test_class = "srcartifacts.SrcArtifactsTest", + deps = [ + "@maven//:com_google_truth_truth", + "@maven//:junit_junit", + ], +) + +create_dir( + name = "dir/java", + srcs = [ + "JavaInJavaDir.java", + ], + subdir = "srcartifacts", +) + +create_dir( + name = "dir/kotlin", + srcs = [ + "KtInKotlinDir.kt", + ], + subdir = "srcartifacts", +) + +create_dir( + name = "dir/empty", + srcs = [], + subdir = "srcartifacts/empty", +) + +create_dir( + name = "dir/resources", + srcs = [ + create_file( + name = "resources_in_resources_dir.txt", + content = "Test resource content.", + ), + ], + subdir = "resources", +) + +genrule( + name = "JavaSrcjar_gen", + srcs = [":libJavaSrcjar_lib-src.jar"], + outs = ["JavaSrcjar.srcjar"], + cmd = "cp $(location :libJavaSrcjar_lib-src.jar) $(location :JavaSrcjar.srcjar)", +) + +java_library( + name = "JavaSrcjar_lib", + srcs = ["JavaSrcjar.java"], + tags = ["manual"], +) + +kt_jvm_library( + name = "empty_java_tree_artifact", + srcs = [ + create_dir( + name = "dir/empty_java/java", + srcs = [], + subdir = "srcartifacts", + ), + ], +) + +kt_jvm_library( + name = "empty_kotlin_tree_artifact", + srcs = [ + create_dir( + name = "dir/empty_kotlin/kotlin", + srcs = [], + subdir = "srcartifacts", + ), + ], +) + +build_test( + name = "empty_dirs_build_test", + targets = [ + "empty_java_tree_artifact", + "empty_kotlin_tree_artifact", + ], +) diff --git a/tests/jvm/java/srcartifacts/JavaInJavaDir.java b/tests/jvm/java/srcartifacts/JavaInJavaDir.java new file mode 100644 index 0000000..70aa7c9 --- /dev/null +++ b/tests/jvm/java/srcartifacts/JavaInJavaDir.java @@ -0,0 +1,31 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package srcartifacts; + +import java.util.Set; + +final class JavaInJavaDir implements SrcArtifact { + @Override + public Set<Class<? extends SrcArtifact>> getAllSrcArtifacts() { + return Set.of( + JavaInJavaDir.class, // + JavaSrc.class, + JavaSrcjar.class, + KtInKotlinDir.class, + KtSrc.class); + } +} diff --git a/tests/jvm/java/srcartifacts/JavaSrc.java b/tests/jvm/java/srcartifacts/JavaSrc.java new file mode 100644 index 0000000..4fdb1c7 --- /dev/null +++ b/tests/jvm/java/srcartifacts/JavaSrc.java @@ -0,0 +1,31 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package srcartifacts; + +import java.util.Set; + +final class JavaSrc implements SrcArtifact { + @Override + public Set<Class<? extends SrcArtifact>> getAllSrcArtifacts() { + return Set.of( + JavaInJavaDir.class, // + JavaSrc.class, + JavaSrcjar.class, + KtInKotlinDir.class, + KtSrc.class); + } +} diff --git a/tests/jvm/java/srcartifacts/JavaSrcjar.java b/tests/jvm/java/srcartifacts/JavaSrcjar.java new file mode 100644 index 0000000..1be65d5 --- /dev/null +++ b/tests/jvm/java/srcartifacts/JavaSrcjar.java @@ -0,0 +1,31 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package srcartifacts; + +import java.util.Set; + +final class JavaSrcjar implements SrcArtifact { + @Override + public Set<Class<? extends SrcArtifact>> getAllSrcArtifacts() { + return Set.of( + JavaInJavaDir.class, // + JavaSrc.class, + JavaSrcjar.class, + KtInKotlinDir.class, + KtSrc.class); + } +} diff --git a/tests/jvm/java/srcartifacts/KtInKotlinDir.kt b/tests/jvm/java/srcartifacts/KtInKotlinDir.kt new file mode 100644 index 0000000..dd2b96d --- /dev/null +++ b/tests/jvm/java/srcartifacts/KtInKotlinDir.kt @@ -0,0 +1,29 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package srcartifacts + +class KtInKotlinDir() : SrcArtifact { + override fun getAllSrcArtifacts(): Set<Class<out SrcArtifact>> { + return setOf( + JavaInJavaDir::class.java, + JavaSrc::class.java, + JavaSrcjar::class.java, + KtInKotlinDir::class.java, + KtSrc::class.java, + ) + } +} diff --git a/tests/jvm/java/srcartifacts/KtSrc.kt b/tests/jvm/java/srcartifacts/KtSrc.kt new file mode 100644 index 0000000..cca27dc --- /dev/null +++ b/tests/jvm/java/srcartifacts/KtSrc.kt @@ -0,0 +1,29 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package srcartifacts + +class KtSrc() : SrcArtifact { + override fun getAllSrcArtifacts(): Set<Class<out SrcArtifact>> { + return setOf( + JavaInJavaDir::class.java, + JavaSrc::class.java, + JavaSrcjar::class.java, + KtInKotlinDir::class.java, + KtSrc::class.java, + ) + } +} diff --git a/tests/jvm/java/srcartifacts/SrcArtifactsTest.kt b/tests/jvm/java/srcartifacts/SrcArtifactsTest.kt new file mode 100644 index 0000000..0622804 --- /dev/null +++ b/tests/jvm/java/srcartifacts/SrcArtifactsTest.kt @@ -0,0 +1,58 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package srcartifacts + +import com.google.common.truth.Truth.assertThat +import java.nio.charset.StandardCharsets +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +interface SrcArtifact { + fun getAllSrcArtifacts(): Set<Class<out SrcArtifact>> +} + +@RunWith(JUnit4::class) +class SrcArtifactsTest { + + @Test + fun allSrcArtifactsInterop() { + val allSrcArtifacts = + setOf( + JavaInJavaDir::class.java, + JavaSrc::class.java, + JavaSrcjar::class.java, + KtInKotlinDir::class.java, + KtSrc::class.java, + ) + + for (artifact in allSrcArtifacts) { + val instance = artifact.getDeclaredConstructor().newInstance() + assertThat(instance.getAllSrcArtifacts()).isEqualTo(allSrcArtifacts) + } + } + + @Test + fun resourceFileContent() { + val fileContent = + javaClass.classLoader + .getResourceAsStream("resources/resources_in_resources_dir.txt") + .use { it.readAllBytes() } + .toString(StandardCharsets.UTF_8) + assertThat(fileContent).isEqualTo("Test resource content.\n") + } +} diff --git a/toolchains/kotlin_jvm/BUILD b/toolchains/kotlin_jvm/BUILD new file mode 100644 index 0000000..587d3a9 --- /dev/null +++ b/toolchains/kotlin_jvm/BUILD @@ -0,0 +1,50 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Kotlin/JVM toolchain.""" + +load(":kt_jvm_toolchains.bzl", "kt_jvm_toolchains") +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + +licenses(["notice"]) + +package(default_visibility = ["//:internal"]) + +toolchain_type(name = kt_jvm_toolchains.name) + +# Toolchain resolution must match :kt_jvm_toolchain_impl. Therefore, there's no +# need for platform-specific toolchain declarations. +toolchain( + name = "kt_jvm_toolchain", + toolchain = ":kt_jvm_toolchain_impl", + toolchain_type = kt_jvm_toolchains.type, +) + +alias( + name = "kt_jvm_toolchain_impl", + actual = select({ + "@bazel_platforms//os:macos": ":kt_jvm_toolchain_macos_impl", + "//conditions:default": ":kt_jvm_toolchain_default_impl", + }), + visibility = ["//visibility:public"], +) + +kt_jvm_toolchains.declare( + name = "kt_jvm_toolchain_macos_impl", + enable_turbine_direct = False, +) + +kt_jvm_toolchains.declare( + name = "kt_jvm_toolchain_default_impl", +) diff --git a/toolchains/kotlin_jvm/java_toolchains.bzl b/toolchains/kotlin_jvm/java_toolchains.bzl new file mode 100644 index 0000000..63dec4e --- /dev/null +++ b/toolchains/kotlin_jvm/java_toolchains.bzl @@ -0,0 +1,28 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Java toolchain for Kotlin.""" + +_ATTRS = dict( + _java_toolchain = attr.label( + default = Label( + "@bazel_tools//tools/jdk:current_java_toolchain", + ), + ), +) + +java_toolchains = struct( + get = lambda ctx: ctx.attr._java_toolchain[java_common.JavaToolchainInfo], + attrs = _ATTRS, +) diff --git a/toolchains/kotlin_jvm/kt_jvm_toolchains.bzl b/toolchains/kotlin_jvm/kt_jvm_toolchains.bzl new file mode 100644 index 0000000..0b9c610 --- /dev/null +++ b/toolchains/kotlin_jvm/kt_jvm_toolchains.bzl @@ -0,0 +1,257 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Kotlin toolchain.""" + +# Work around to toolchains in Google3. +KtJvmToolchainInfo = provider() + +KT_VERSION = "v1_7_10" + +KT_LANG_VERSION = "1.7" + +# Kotlin JVM toolchain type label +_TYPE = Label("//toolchains/kotlin_jvm:kt_jvm_toolchain_type") + +def _kotlinc_common_flags(ctx, other_flags): + """Returns kotlinc flags to use in all compilations.""" + args = [ + # We're supplying JDK in bootclasspath explicitly instead + "-no-jdk", + + # stdlib included in merged_deps + "-no-stdlib", + + # The bytecode format to emit + "-jvm-target", + ctx.attr.jvm_target, + + # Emit bytecode with parameter names + "-java-parameters", + + # Allow default method declarations, akin to what javac emits (b/110378321). + "-Xjvm-default=all", + + # Trust JSR305 nullness type qualifier nicknames the same as @Nonnull/@Nullable + # (see https://kotlinlang.org/docs/reference/java-interop.html#jsr-305-support) + "-Xjsr305=strict", + + # Trust go/JSpecify nullness annotations + # (see https://kotlinlang.org/docs/whatsnew1520.html#support-for-jspecify-nullness-annotations) + "-Xjspecify-annotations=strict", + + # Trust annotations on type arguments, etc. + # (see https://kotlinlang.org/docs/java-interop.html#annotating-type-arguments-and-type-parameters) + "-Xtype-enhancement-improvements-strict-mode", + + # TODO: Remove this as the default setting (probably Kotlin 1.7) + "-Xenhance-type-parameter-types-to-def-not-null=true", + + # Explicitly set language version so we can update compiler separate from language version + "-language-version", + ctx.attr.kotlin_language_version, + + # Enable type annotations in the JVM bytecode (b/170647926) + "-Xemit-jvm-type-annotations", + + # TODO: Temporarily disable 1.5's sam wrapper conversion + "-Xsam-conversions=class", + + # We don't want people to use experimental APIs, but if they do, we want them to use @OptIn + "-opt-in=kotlin.RequiresOptIn", + + # Don't complain when using old builds or release candidate builds + "-Xskip-prerelease-check", + + # Allows a no source files to create an empty jar. + "-Xallow-no-source-files", + ] + other_flags + + # --define=extra_kt_jvm_opts is for overriding from command line. + # (Last wins in repeated --define=foo= use, so use --define=bar= instead.) + extra_kt_jvm_opts = ctx.var.get("extra_kt_jvm_opts", default = None) + if extra_kt_jvm_opts: + args.extend([o for o in extra_kt_jvm_opts.split(" ") if o]) + return args + +def _kotlinc_ide_flags(ctx): + return _kotlinc_common_flags(ctx, other_flags = []) + +def _kotlinc_cli_flags(ctx): + return _kotlinc_common_flags(ctx, other_flags = [ + # Silence all warning-level diagnostics + "-nowarn", + ]) + +def _kt_jvm_toolchain_impl(ctx): + kt_jvm_toolchain = dict( + build_marker = ctx.file.build_marker, + coverage_instrumenter = ctx.attr.coverage_instrumenter[DefaultInfo].files_to_run, + # Don't require JavaInfo provider for integration test convenience. + coverage_runtime = ctx.attr.coverage_runtime[JavaInfo] if JavaInfo in ctx.attr.coverage_runtime else None, + genclass = ctx.file.genclass, + jar_tool = ctx.attr.jar_tool[DefaultInfo].files_to_run, + java_runtime = ctx.attr.java_runtime, + jvm_abi_gen_plugin = ctx.file.jvm_abi_gen_plugin, + kotlin_annotation_processing = ctx.file.kotlin_annotation_processing, + kotlin_compiler = ctx.attr.kotlin_compiler[DefaultInfo].files_to_run, + kotlin_language_version = ctx.attr.kotlin_language_version, + kotlin_libs = [JavaInfo(compile_jar = jar, output_jar = jar) for jar in ctx.files.kotlin_libs], + kotlin_sdk_libraries = ctx.attr.kotlin_sdk_libraries, + kotlinc_cli_flags = _kotlinc_cli_flags(ctx), + kotlinc_ide_flags = _kotlinc_ide_flags(ctx), + proguard_whitelister = ctx.attr.proguard_whitelister[DefaultInfo].files_to_run, + turbine = ctx.file.turbine, + turbine_direct = ctx.file.turbine_direct if ctx.attr.enable_turbine_direct else None, + turbine_jsa = ctx.file.turbine_jsa, + ) + return [ + platform_common.ToolchainInfo(**kt_jvm_toolchain), + KtJvmToolchainInfo(**kt_jvm_toolchain), + ] + +_kt_jvm_toolchain_internal = rule( + name = "kt_jvm_toolchain", + attrs = dict( + build_marker = attr.label( + default = "//tools:build_marker", + allow_single_file = [".jar"], + ), + coverage_instrumenter = attr.label( + default = "//tools/coverage:offline_instrument", + cfg = "exec", + executable = True, + ), + coverage_runtime = attr.label( + default = "@maven//:org_jacoco_org_jacoco_agent", + ), + enable_turbine_direct = attr.bool( + # If disabled, the value of turbine_direct will be ignored. + # Starlark doesn't allow None to override default-valued attributes: + default = True, + ), + genclass = attr.label( + default = "@bazel_tools//tools/jdk:GenClass_deploy.jar", + cfg = "exec", + allow_single_file = True, + ), + jar_tool = attr.label( + default = "@bazel_tools//tools/jdk:jar", + executable = True, + allow_files = True, + cfg = "exec", + ), + java_runtime = attr.label( + default = "@bazel_tools//tools/jdk:current_java_runtime", + cfg = "exec", + allow_files = True, + ), + jvm_abi_gen_plugin = attr.label( + default = "@kotlinc//:jvm_abi_gen_plugin", + cfg = "exec", + allow_single_file = [".jar"], + ), + jvm_target = attr.string( + doc = "The value to pass as -jvm-target, indicating the bytecode format to emit.", + ), + kotlin_annotation_processing = attr.label( + default = "@kotlinc//:kotlin_annotation_processing", + cfg = "exec", + allow_single_file = True, + ), + kotlin_compiler = attr.label( + default = "@kotlinc//:kotlin_compiler", + cfg = "exec", + executable = True, + ), + kotlin_language_version = attr.string( + default = KT_LANG_VERSION, + ), + kotlin_libs = attr.label_list( + doc = "The libraries required during all Kotlin builds.", + default = [ + "@kotlinc//:kotlin_stdlib", + "@kotlinc//:annotations", + ], + allow_files = [".jar"], + cfg = "target", + ), + kotlin_sdk_libraries = attr.label_list( + doc = "The libraries required to resolve Kotlin code in an IDE.", + default = [ + "@kotlinc//:kotlin_reflect", + "@kotlinc//:kotlin_stdlib", + "@kotlinc//:kotlin_stdlib_jdk7", + "@kotlinc//:kotlin_stdlib_jdk8", + "@kotlinc//:kotlin_test_not_testonly", + ], + cfg = "target", + ), + proguard_whitelister = attr.label( + default = "@bazel_tools//tools/jdk:proguard_whitelister", + cfg = "exec", + ), + runtime = attr.label_list( + # This attribute has a "magic" name recognized by the native DexArchiveAspect + # (b/78647825). Must list all implicit runtime deps here, this is not limited + # to Kotlin runtime libs. + default = [ + "@kotlinc//:kotlin_stdlib", + "@kotlinc//:annotations", + ], + cfg = "target", + doc = "The Kotlin runtime libraries grouped into one attribute.", + ), + turbine = attr.label( + default = "@bazel_tools//tools/jdk:turbine_direct", + cfg = "exec", + allow_single_file = True, + ), + turbine_direct = attr.label( + executable = True, + cfg = "exec", + allow_single_file = True, + ), + turbine_jsa = attr.label( + cfg = "exec", + allow_single_file = True, + ), + ), + provides = [platform_common.ToolchainInfo], + implementation = _kt_jvm_toolchain_impl, +) + +def _kt_jvm_toolchain(**kwargs): + _kt_jvm_toolchain_internal( + jvm_target = select({ + "//conditions:default": "11", + }), + **kwargs + ) + +_ATTRS = dict( + _toolchain = attr.label( + # TODO: Delete this attr when fixed. + doc = "Magic attribute name for DexArchiveAspect (b/78647825)", + default = "//toolchains/kotlin_jvm:kt_jvm_toolchain_impl", + ), +) + +kt_jvm_toolchains = struct( + name = _TYPE.name, + get = lambda ctx: ctx.toolchains[_TYPE], + type = str(_TYPE), + declare = _kt_jvm_toolchain, + attrs = _ATTRS, +) diff --git a/tools/BUILD b/tools/BUILD new file mode 100644 index 0000000..18f1a9a --- /dev/null +++ b/tools/BUILD @@ -0,0 +1,27 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Description: Kotlin building rules tools + +licenses(["notice"]) + +package(default_visibility = ["//:internal"]) + +# JAR that contains a marker entry, for identifying apps built by rules_kotlin. +genrule( + name = "build_marker", + outs = ["kotlin_build_marker.jar"], + cmd = """$(location @bazel_tools//tools/zip:zipper) c $@ "assets/_kotlin=" """, + tools = ["@bazel_tools//tools/zip:zipper"], +) diff --git a/tools/coverage/BUILD b/tools/coverage/BUILD new file mode 100644 index 0000000..e97ac5d --- /dev/null +++ b/tools/coverage/BUILD @@ -0,0 +1,27 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +licenses(["notice"]) + +sh_binary( + name = "offline_instrument", + srcs = ["bazel_jar_instrumenter.sh"], + data = [ + "//bazel:jacoco_cli", + "@bazel_tools//tools/jdk:jar", + ], + visibility = [ + "//:internal", + ], +) diff --git a/tools/coverage/bazel_jar_instrumenter.sh b/tools/coverage/bazel_jar_instrumenter.sh new file mode 100755 index 0000000..648c6b6 --- /dev/null +++ b/tools/coverage/bazel_jar_instrumenter.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +set -eu + +readonly current_dir="$0.runfiles" +readonly in="$1" +readonly out="$2" +shift 2 + +readonly tmp_dir="$(mktemp -d)" +trap "rm -rf ${tmp_dir}" EXIT + +readonly jacoco="$(ls ${current_dir}/rules_kotlin/bazel/jacoco_cli)" +readonly jar="$(which jar)" + +# Unzip input Jar and run JaCoCo over it +mkdir "${tmp_dir}/classes" +mkdir "${tmp_dir}/instrumented" +unzip -qq -d "${tmp_dir}/classes" "${in}" +"${jacoco}" instrument "${tmp_dir}/classes" --dest "${tmp_dir}/instrumented" >/dev/null + +# Rename input .class files to .class.uninstrumented +find "${tmp_dir}/classes" -name '*.class' -exec mv {} {}.uninstrumented \; + +# Zip all the files together +"${jar}" cf "${out}" -C "${tmp_dir}/instrumented" . +"${jar}" uf "${out}" -C "${tmp_dir}/classes" . +"${jar}" uf "${out}" "$@" |