From e363a1228d6884025f713cf543a319d6b8e8ac36 Mon Sep 17 00:00:00 2001 From: strangepleasures Date: Mon, 12 Feb 2024 11:17:32 +0000 Subject: [PATCH] KT-65404 KAPT should print a warning if stub generation is triggered for an interface with method bodies but without -Xjvm-default=all or -Xjvm-default=all-compatibility Merge-request: KT-MR-14139 Merged-by: Pavel Mikhailovskii --- .../test/AbstractKaptToolIntegrationTest.kt | 9 +++++---- .../Test.kt | 11 +++++++++++ .../build.txt | 18 ++++++++++++++++++ .../defaultMethodsAllNoWarning/Test.kt | 11 +++++++++++ .../defaultMethodsAllNoWarning/build.txt | 18 ++++++++++++++++++ .../defaultMethodsWarning/Test.kt | 11 +++++++++++ .../defaultMethodsWarning/build.txt | 18 ++++++++++++++++++ .../Kapt4ToolIntegrationTestGenerated.java | 18 ++++++++++++++++++ .../jetbrains/kotlin/kapt4/StubGenerator.kt | 14 +++++++++++++- 9 files changed, 123 insertions(+), 5 deletions(-) create mode 100644 plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsAllCompatibilityNoWarning/Test.kt create mode 100644 plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsAllCompatibilityNoWarning/build.txt create mode 100644 plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsAllNoWarning/Test.kt create mode 100644 plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsAllNoWarning/build.txt create mode 100644 plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsWarning/Test.kt create mode 100644 plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsWarning/build.txt diff --git a/plugins/kapt3/kapt3-cli/test/org/jetbrains/kotlin/kapt/cli/test/AbstractKaptToolIntegrationTest.kt b/plugins/kapt3/kapt3-cli/test/org/jetbrains/kotlin/kapt/cli/test/AbstractKaptToolIntegrationTest.kt index a816c3b267c..1b89c65145c 100644 --- a/plugins/kapt3/kapt3-cli/test/org/jetbrains/kotlin/kapt/cli/test/AbstractKaptToolIntegrationTest.kt +++ b/plugins/kapt3/kapt3-cli/test/org/jetbrains/kotlin/kapt/cli/test/AbstractKaptToolIntegrationTest.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.kapt.cli.test import com.intellij.openapi.util.SystemInfo +import com.intellij.openapi.util.text.StringUtil.convertLineSeparators import org.jetbrains.kotlin.cli.common.arguments.readArgumentsFromArgFile import org.jetbrains.kotlin.test.services.JUnit5Assertions import org.jetbrains.kotlin.test.util.KtTestUtil @@ -53,10 +54,10 @@ abstract class AbstractKaptToolIntegrationTest { "javac" -> runJavac(section.args) "java" -> runJava(section.args) "output" -> { - val output = File(tmpdir, "processOutput.txt").readText() - val expected = section.content.trim() - JUnit5Assertions.assertTrue(output.contains(expected)) { - "Output\"$output\" doesn't contain the expected string \"$expected\"" + val output = convertLineSeparators(File(tmpdir, "processOutput.txt").readText().trim()) + val expected = convertLineSeparators(section.content.trim()) + JUnit5Assertions.assertEquals(expected, output) { + "Output\"$output\" is different from the expected string \"$expected\"" } } "after" -> {} diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsAllCompatibilityNoWarning/Test.kt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsAllCompatibilityNoWarning/Test.kt new file mode 100644 index 00000000000..4a29f5526ae --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsAllCompatibilityNoWarning/Test.kt @@ -0,0 +1,11 @@ +package test + +interface I1 { + fun foo() {} +} + +interface I2 { + fun bar() {} +} + +class C: I1, I2 \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsAllCompatibilityNoWarning/build.txt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsAllCompatibilityNoWarning/build.txt new file mode 100644 index 00000000000..b56ea7354b4 --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsAllCompatibilityNoWarning/build.txt @@ -0,0 +1,18 @@ +# mkdir +output/stubs + +# kapt +-Xjvm-default=all-compatibility +-language-version 2.0 +-Xuse-kapt4 +-Kapt-mode=stubs +-Kapt-stubs=output/stubs +-Kapt-classes=output/classes +-Kapt-sources=output/sources +-Kapt-classpath=output/ap +-d output/classes +-cp %KOTLIN_STDLIB% +Test.kt + +# output +warning: k2 kapt is an experimental feature. Use with caution. \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsAllNoWarning/Test.kt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsAllNoWarning/Test.kt new file mode 100644 index 00000000000..4a29f5526ae --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsAllNoWarning/Test.kt @@ -0,0 +1,11 @@ +package test + +interface I1 { + fun foo() {} +} + +interface I2 { + fun bar() {} +} + +class C: I1, I2 \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsAllNoWarning/build.txt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsAllNoWarning/build.txt new file mode 100644 index 00000000000..bfcb338366d --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsAllNoWarning/build.txt @@ -0,0 +1,18 @@ +# mkdir +output/stubs + +# kapt +-Xjvm-default=all +-language-version 2.0 +-Xuse-kapt4 +-Kapt-mode=stubs +-Kapt-stubs=output/stubs +-Kapt-classes=output/classes +-Kapt-sources=output/sources +-Kapt-classpath=output/ap +-d output/classes +-cp %KOTLIN_STDLIB% +Test.kt + +# output +warning: k2 kapt is an experimental feature. Use with caution. \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsWarning/Test.kt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsWarning/Test.kt new file mode 100644 index 00000000000..4a29f5526ae --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsWarning/Test.kt @@ -0,0 +1,11 @@ +package test + +interface I1 { + fun foo() {} +} + +interface I2 { + fun bar() {} +} + +class C: I1, I2 \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsWarning/build.txt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsWarning/build.txt new file mode 100644 index 00000000000..a2ad870dc2c --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsWarning/build.txt @@ -0,0 +1,18 @@ +# mkdir +output/stubs + +# kapt +-language-version 2.0 +-Xuse-kapt4 +-Kapt-mode=stubs +-Kapt-stubs=output/stubs +-Kapt-classes=output/classes +-Kapt-sources=output/sources +-Kapt-classpath=output/ap +-d output/classes +-cp %KOTLIN_STDLIB% +Test.kt + +# output +warning: k2 kapt is an experimental feature. Use with caution. +warning: [kapt] Support for interface methods with bodies in Kapt requires -Xjvm-default=all or -Xjvm-default=all-compatibility compiler option \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/tests-gen/org/jetbrains/kotlin/kapt/cli/test/Kapt4ToolIntegrationTestGenerated.java b/plugins/kapt3/kapt3-cli/tests-gen/org/jetbrains/kotlin/kapt/cli/test/Kapt4ToolIntegrationTestGenerated.java index ce5d00263f0..fe5e1629450 100644 --- a/plugins/kapt3/kapt3-cli/tests-gen/org/jetbrains/kotlin/kapt/cli/test/Kapt4ToolIntegrationTestGenerated.java +++ b/plugins/kapt3/kapt3-cli/tests-gen/org/jetbrains/kotlin/kapt/cli/test/Kapt4ToolIntegrationTestGenerated.java @@ -42,6 +42,24 @@ public class Kapt4ToolIntegrationTestGenerated extends AbstractKapt4ToolIntegrat runTest("plugins/kapt3/kapt3-cli/testData/integration-kapt4/correctErrorTypesOn/"); } + @Test + @TestMetadata("defaultMethodsAllCompatibilityNoWarning") + public void testDefaultMethodsAllCompatibilityNoWarning() throws Exception { + runTest("plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsAllCompatibilityNoWarning/"); + } + + @Test + @TestMetadata("defaultMethodsAllNoWarning") + public void testDefaultMethodsAllNoWarning() throws Exception { + runTest("plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsAllNoWarning/"); + } + + @Test + @TestMetadata("defaultMethodsWarning") + public void testDefaultMethodsWarning() throws Exception { + runTest("plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultMethodsWarning/"); + } + @Test @TestMetadata("defaultPackage") public void testDefaultPackage() throws Exception { diff --git a/plugins/kapt4/src/org/jetbrains/kotlin/kapt4/StubGenerator.kt b/plugins/kapt4/src/org/jetbrains/kotlin/kapt4/StubGenerator.kt index eac15e2544b..219d9162ed3 100644 --- a/plugins/kapt4/src/org/jetbrains/kotlin/kapt4/StubGenerator.kt +++ b/plugins/kapt4/src/org/jetbrains/kotlin/kapt4/StubGenerator.kt @@ -10,6 +10,7 @@ package org.jetbrains.kotlin.kapt4 import com.google.common.collect.HashMultimap import com.google.common.collect.Multimap import com.intellij.lang.ASTNode +import com.intellij.lang.jvm.JvmModifier import com.intellij.psi.* import com.intellij.psi.impl.source.tree.LeafPsiElement import org.jetbrains.kotlin.KtNodeTypes @@ -25,6 +26,8 @@ import org.jetbrains.kotlin.asJava.elements.* import org.jetbrains.kotlin.asJava.findFacadeClass import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.builtins.StandardNames +import org.jetbrains.kotlin.config.JvmAnalysisFlags +import org.jetbrains.kotlin.config.JvmDefaultMode import org.jetbrains.kotlin.config.LanguageVersion import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils.offsetToLineAndColumn import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil @@ -46,6 +49,7 @@ import org.jetbrains.kotlin.utils.toMetadataVersion import org.jetbrains.kotlin.kapt3.base.KaptOptions import org.jetbrains.kotlin.kapt3.base.util.KaptLogger import org.jetbrains.kotlin.kapt3.stubs.MembersPositionComparator +import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.psi.psiUtil.children import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType import org.jetbrains.kotlin.utils.Printer @@ -66,8 +70,10 @@ internal fun generateStubs( return emptyMap() } } + val jvmDefaultMode = module.languageVersionSettings.getFlag(JvmAnalysisFlags.jvmDefaultMode) return analyze(module) { - StubGenerator(files.filterIsInstance(), options, logger, metadataRenderer, overriddenMetadataVersion).generateStubs() + StubGenerator(files.filterIsInstance(), options, logger, metadataRenderer, overriddenMetadataVersion, jvmDefaultMode) + .generateStubs() } } @@ -85,6 +91,7 @@ private class StubGenerator( private val logger: KaptLogger, private val metadataRenderer: (Printer.(Metadata) -> Unit)? = null, private val overriddenMetadataVersion: BinaryVersion? = null, + private val jvmDefaultMode: JvmDefaultMode, ) { private val strictMode = options[KaptFlag.STRICT] private val stripMetadata = options[KaptFlag.STRIP_METADATA] @@ -513,6 +520,11 @@ private class StubGenerator( if (!(modifierListOwner is PsiMethod && modifierListOwner.isConstructor && modifierListOwner.containingClass?.isEnum == true) && (modifierListOwner !is PsiEnumConstant)) { for (modifier in PsiModifier.MODIFIERS.filter(modifierListOwner::hasModifierProperty)) { if (modifier == PsiModifier.PRIVATE && (modifierListOwner as? PsiMember)?.containingClass?.isInterface == true) continue + + if (!jvmDefaultMode.isEnabled && modifier == PsiModifier.DEFAULT) { + onError("Support for interface methods with bodies in Kapt requires -Xjvm-default=all or -Xjvm-default=all-compatibility compiler option") + } + if ((modifier != PsiModifier.FINAL && modifier != PsiModifier.ABSTRACT) || !(modifierListOwner is PsiClass && modifierListOwner.isEnum)) { printWithNoIndent(modifier, " ") }