diff --git a/idea/resources/META-INF/kotlinx-serialization.xml b/idea/resources/META-INF/kotlinx-serialization.xml
index 4ad16af7a6a..3e2a22229ab 100644
--- a/idea/resources/META-INF/kotlinx-serialization.xml
+++ b/idea/resources/META-INF/kotlinx-serialization.xml
@@ -5,5 +5,6 @@
+
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationErrors.java b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationErrors.java
index 7a0d339e30e..5616ece19ec 100644
--- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationErrors.java
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationErrors.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@@ -32,6 +32,8 @@ public interface SerializationErrors {
DiagnosticFactory0 TRANSIENT_IS_REDUNDANT = DiagnosticFactory0.create(WARNING);
+ DiagnosticFactory0 INCORRECT_TRANSIENT = DiagnosticFactory0.create(WARNING);
+
@SuppressWarnings("UnusedDeclaration")
Object _initializer = new Object() {
{
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationPluginDeclarationChecker.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationPluginDeclarationChecker.kt
index 5f44776c2dc..2729b12a3fb 100644
--- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationPluginDeclarationChecker.kt
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationPluginDeclarationChecker.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@@ -14,10 +14,14 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
+import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
+import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
import org.jetbrains.kotlin.resolve.hasBackingField
import org.jetbrains.kotlin.resolve.isInlineClassType
+import org.jetbrains.kotlin.resolve.jvm.annotations.TRANSIENT_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationDescriptor
+import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.supertypes
import org.jetbrains.kotlin.util.slicedMap.Slices
@@ -37,10 +41,27 @@ open class SerializationPluginDeclarationChecker : DeclarationChecker {
if (!canBeSerializedInternally(descriptor, declaration, context.trace)) return
if (declaration !is KtPureClassOrObject) return
val props = buildSerializableProperties(descriptor, context.trace) ?: return
+ checkCorrectTransientAnnotationIsUsed(descriptor, props.serializableProperties, context.trace)
checkTransients(declaration, context.trace)
analyzePropertiesSerializers(context.trace, descriptor, props.serializableProperties)
}
+ private fun checkCorrectTransientAnnotationIsUsed(
+ descriptor: ClassDescriptor,
+ properties: List,
+ trace: BindingTrace
+ ) {
+ if (descriptor.getSuperInterfaces().any { it.fqNameSafe.asString() == "java.io.Serializable" }) return // do not check
+ for (prop in properties) {
+ if (prop.transient) continue // correct annotation is used
+ val incorrectTransient = prop.descriptor.backingField?.annotations?.findAnnotation(TRANSIENT_ANNOTATION_FQ_NAME)
+ if (incorrectTransient != null) {
+ val elementToReport = incorrectTransient.source.getPsi() ?: prop.descriptor.findPsi() ?: continue
+ trace.report(SerializationErrors.INCORRECT_TRANSIENT.on(elementToReport))
+ }
+ }
+ }
+
private fun canBeSerializedInternally(descriptor: ClassDescriptor, declaration: KtDeclaration, trace: BindingTrace): Boolean {
if (descriptor.isSerializableEnumWithMissingSerializer()) {
val declarationToReport = declaration.modifierList ?: declaration
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationPluginErrorsRendering.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationPluginErrorsRendering.kt
index f541b3ec908..f071e10e63f 100644
--- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationPluginErrorsRendering.kt
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/SerializationPluginErrorsRendering.kt
@@ -65,5 +65,9 @@ object SerializationPluginErrorsRendering : DefaultErrorMessages.Extension {
SerializationErrors.TRANSIENT_IS_REDUNDANT,
"Property does not have backing field which makes it non-serializable and therefore @Transient is redundant"
)
+ MAP.put(
+ SerializationErrors.INCORRECT_TRANSIENT,
+ "@kotlin.jvm.Transient does not affect @Serializable classes. Please use @kotlinx.serialization.Transient instead."
+ )
}
}
\ No newline at end of file
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/NamingConventions.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/NamingConventions.kt
index cac1db59996..9a3e2e8b3d8 100644
--- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/NamingConventions.kt
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/NamingConventions.kt
@@ -23,7 +23,7 @@ object SerializationAnnotations {
val serializerAnnotationFqName = FqName("kotlinx.serialization.Serializer")
internal val serialNameAnnotationFqName = FqName("kotlinx.serialization.SerialName")
internal val requiredAnnotationFqName = FqName("kotlinx.serialization.Required")
- internal val serialTransientFqName = FqName("kotlinx.serialization.Transient")
+ val serialTransientFqName = FqName("kotlinx.serialization.Transient")
internal val serialInfoFqName = FqName("kotlinx.serialization.SerialInfo")
internal val contextualFqName = FqName("kotlinx.serialization.ContextualSerialization") // this one is deprecated
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/test/org/jetbrains/kotlinx/serialization/SerializationPluginDiagnosticTestGenerated.java b/plugins/kotlin-serialization/kotlin-serialization-compiler/test/org/jetbrains/kotlinx/serialization/SerializationPluginDiagnosticTestGenerated.java
index 2a07c127c73..04f8eacec97 100644
--- a/plugins/kotlin-serialization/kotlin-serialization-compiler/test/org/jetbrains/kotlinx/serialization/SerializationPluginDiagnosticTestGenerated.java
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/test/org/jetbrains/kotlinx/serialization/SerializationPluginDiagnosticTestGenerated.java
@@ -25,7 +25,9 @@ public class SerializationPluginDiagnosticTestGenerated extends AbstractSerializ
}
public void testAllFilesPresentInDiagnostics() throws Exception {
- KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics"), Pattern.compile("^(.+)\\.kt$"), null, true);
+ KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File(
+ "plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics"), Pattern.compile("^(.+)\\.kt$"), null,
+ true);
}
@TestMetadata("DuplicateSerialName.kt")
@@ -33,6 +35,16 @@ public class SerializationPluginDiagnosticTestGenerated extends AbstractSerializ
runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/DuplicateSerialName.kt");
}
+ @TestMetadata("IncorrectTransient.kt")
+ public void testIncorrectTransient() throws Exception {
+ runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/IncorrectTransient.kt");
+ }
+
+ @TestMetadata("IncorrectTransient2.kt")
+ public void testIncorrectTransient2() throws Exception {
+ runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/IncorrectTransient2.kt");
+ }
+
@TestMetadata("LazyRecursionBug.kt")
public void testLazyRecursionBug() throws Exception {
runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/LazyRecursionBug.kt");
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/IncorrectTransient.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/IncorrectTransient.kt
new file mode 100644
index 00000000000..b1eef1936d2
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/IncorrectTransient.kt
@@ -0,0 +1,12 @@
+// !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE
+// WITH_RUNTIME
+// SKIP_TXT
+
+import kotlinx.serialization.Serializable
+import java.io.Serializable as JavaSerializable
+
+@Serializable
+class Data(val x: Int, @Transient val y: String)
+
+@Serializable
+class Data2(val x: Int, @Transient val y: String) : JavaSerializable
\ No newline at end of file
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/IncorrectTransient2.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/IncorrectTransient2.kt
new file mode 100644
index 00000000000..8c1e812a131
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/IncorrectTransient2.kt
@@ -0,0 +1,20 @@
+// !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE
+// WITH_RUNTIME
+// SKIP_TXT
+
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.Transient
+import java.io.Serializable as JavaSerializable
+import kotlin.jvm.Transient as JavaTransient
+
+@Serializable
+class Data(val x: Int, @Transient val y: String = "a")
+
+@Serializable
+class Data2(val x: Int, @Transient val y: String = "a") : JavaSerializable
+
+@Serializable
+class Data3(val x: Int, @Transient @JavaTransient val y: String = "a") : JavaSerializable
+
+@Serializable
+class Data4(val x: Int, @JavaTransient val y: String)
\ No newline at end of file
diff --git a/plugins/kotlin-serialization/kotlin-serialization-ide/build.gradle.kts b/plugins/kotlin-serialization/kotlin-serialization-ide/build.gradle.kts
index 80119173823..2ef3944b795 100644
--- a/plugins/kotlin-serialization/kotlin-serialization-ide/build.gradle.kts
+++ b/plugins/kotlin-serialization/kotlin-serialization-ide/build.gradle.kts
@@ -15,6 +15,9 @@ dependencies {
compile(project(":idea:idea-maven"))
compile(project(":plugins:annotation-based-compiler-plugins-ide-support"))
compileOnly(intellijDep())
+ Platform[192].orHigher {
+ compileOnly(intellijPluginDep("java"))
+ }
excludeInAndroidStudio(rootProject) { compileOnly(intellijPluginDep("maven")) }
compileOnly(intellijPluginDep("gradle"))
@@ -30,5 +33,5 @@ sourceSets {
runtimeJar()
projectTest(parallel = true) {
-
+
}
\ No newline at end of file
diff --git a/plugins/kotlin-serialization/kotlin-serialization-ide/src/org/jetbrains/kotlinx/serialization/idea/quickfixes/IncorrectTransientQuickFix.kt b/plugins/kotlin-serialization/kotlin-serialization-ide/src/org/jetbrains/kotlinx/serialization/idea/quickfixes/IncorrectTransientQuickFix.kt
new file mode 100644
index 00000000000..cca28360931
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-ide/src/org/jetbrains/kotlinx/serialization/idea/quickfixes/IncorrectTransientQuickFix.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlinx.serialization.idea.quickfixes
+
+import com.intellij.codeInsight.intention.IntentionAction
+import com.intellij.openapi.editor.Editor
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiElement
+import org.jetbrains.kotlin.diagnostics.Diagnostic
+import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
+import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
+import org.jetbrains.kotlin.idea.util.ImportInsertHelperImpl
+import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlinx.serialization.compiler.diagnostic.SerializationErrors
+import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
+
+internal class AddKotlinxSerializationTransientImportQuickFix(expression: PsiElement) :
+ KotlinQuickFixAction(expression) {
+ override fun invoke(project: Project, editor: Editor?, file: KtFile) {
+ // Do not use Helper itself because it does not insert import on conflict;
+ // so it will always fail because k.jvm.Transient is always in auto-import
+ ImportInsertHelperImpl.addImport(project, file, SerializationAnnotations.serialTransientFqName, allUnder = false)
+ }
+
+ override fun getFamilyName(): String = text
+
+ override fun getText(): String = "Import ${SerializationAnnotations.serialTransientFqName}"
+
+ object Factory : KotlinSingleIntentionActionFactory() {
+ override fun createAction(diagnostic: Diagnostic): IntentionAction? {
+ if (diagnostic.factory != SerializationErrors.INCORRECT_TRANSIENT) return null
+ val castedDiagnostic = SerializationErrors.INCORRECT_TRANSIENT.cast(diagnostic)
+
+ val element = castedDiagnostic.psiElement
+
+ return AddKotlinxSerializationTransientImportQuickFix(element)
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/kotlin-serialization/kotlin-serialization-ide/src/org/jetbrains/kotlinx/serialization/idea/quickfixes/SerializationQuickFixContributor.kt b/plugins/kotlin-serialization/kotlin-serialization-ide/src/org/jetbrains/kotlinx/serialization/idea/quickfixes/SerializationQuickFixContributor.kt
new file mode 100644
index 00000000000..df870ab45ba
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-ide/src/org/jetbrains/kotlinx/serialization/idea/quickfixes/SerializationQuickFixContributor.kt
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlinx.serialization.idea.quickfixes
+
+import org.jetbrains.kotlin.idea.quickfix.QuickFixContributor
+import org.jetbrains.kotlin.idea.quickfix.QuickFixes
+import org.jetbrains.kotlinx.serialization.compiler.diagnostic.SerializationErrors
+
+class SerializationQuickFixContributor : QuickFixContributor {
+ override fun registerQuickFixes(quickFixes: QuickFixes) {
+ quickFixes.register(SerializationErrors.INCORRECT_TRANSIENT, AddKotlinxSerializationTransientImportQuickFix.Factory)
+ }
+}
\ No newline at end of file