From 258e8f73b67de139e361c3a8d7a0ce3efb2cbc7d Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Fri, 22 Sep 2017 17:51:02 +0300 Subject: [PATCH] Expect/actual: add inspection for Suppress("DIAGNOSTIC") migration So #KT-20328 Fixed --- .../MigrateDiagnosticSuppression.html | 8 ++ idea/src/META-INF/plugin.xml | 10 ++ .../MigrateDiagnosticSuppressionInspection.kt | 99 +++++++++++++++++++ .../migrateDiagnosticSuppression/.inspection | 1 + .../migrateDiagnosticSuppression/base.kt | 2 + .../base.kt.after | 2 + .../migrateDiagnosticSuppression/multiple.kt | 6 ++ .../multiple.kt.after | 6 ++ .../migrateDiagnosticSuppression/new.kt | 4 + .../LocalInspectionTestGenerated.java | 27 +++++ 10 files changed, 165 insertions(+) create mode 100644 idea/resources/inspectionDescriptions/MigrateDiagnosticSuppression.html create mode 100644 idea/src/org/jetbrains/kotlin/idea/inspections/MigrateDiagnosticSuppressionInspection.kt create mode 100644 idea/testData/inspectionsLocal/migrateDiagnosticSuppression/.inspection create mode 100644 idea/testData/inspectionsLocal/migrateDiagnosticSuppression/base.kt create mode 100644 idea/testData/inspectionsLocal/migrateDiagnosticSuppression/base.kt.after create mode 100644 idea/testData/inspectionsLocal/migrateDiagnosticSuppression/multiple.kt create mode 100644 idea/testData/inspectionsLocal/migrateDiagnosticSuppression/multiple.kt.after create mode 100644 idea/testData/inspectionsLocal/migrateDiagnosticSuppression/new.kt diff --git a/idea/resources/inspectionDescriptions/MigrateDiagnosticSuppression.html b/idea/resources/inspectionDescriptions/MigrateDiagnosticSuppression.html new file mode 100644 index 00000000000..d10e30878da --- /dev/null +++ b/idea/resources/inspectionDescriptions/MigrateDiagnosticSuppression.html @@ -0,0 +1,8 @@ + + +This inspection reports suppression with old diagnostic names, for example: +
+  @Suppress("HEADER_WITHOUT_IMPLEMENTATION")
+
+ + \ No newline at end of file diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 1d1d11b8309..3271db4703f 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -2612,6 +2612,16 @@ language="kotlin" /> + + diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/MigrateDiagnosticSuppressionInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/MigrateDiagnosticSuppressionInspection.kt new file mode 100644 index 00000000000..7827e61a324 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/MigrateDiagnosticSuppressionInspection.kt @@ -0,0 +1,99 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * 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 org.jetbrains.kotlin.idea.inspections + +import com.intellij.codeInsight.FileModificationService +import com.intellij.codeInspection.* +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.text.StringUtil +import com.intellij.psi.PsiElementVisitor +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.diagnostics.DiagnosticFactory +import org.jetbrains.kotlin.diagnostics.Errors.* +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode + +class MigrateDiagnosticSuppressionInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool { + override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { + return object : KtVisitorVoid() { + + override fun visitAnnotationEntry(annotationEntry: KtAnnotationEntry) { + super.visitAnnotationEntry(annotationEntry) + + if (annotationEntry.calleeExpression?.text != "Suppress") return + val context = annotationEntry.analyze(BodyResolveMode.PARTIAL) + val descriptor = context[BindingContext.ANNOTATION, annotationEntry] ?: return + if (descriptor.fqName != KotlinBuiltIns.FQ_NAMES.suppress) return + + for (argument in annotationEntry.valueArguments) { + val expression = argument.getArgumentExpression() as? KtStringTemplateExpression ?: continue + val text = expression.text + if (text.firstOrNull() != '\"' || text.lastOrNull() != '\"') continue + val newDiagnosticFactory = MIGRATION_MAP[StringUtil.unquoteString(text)] ?: continue + + holder.registerProblem( + expression, + "Diagnostic name should be replaced by the new one", + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, + ReplaceDiagnosticNameFix(newDiagnosticFactory) + ) + } + } + } + } + + class ReplaceDiagnosticNameFix(private val diagnosticFactory: DiagnosticFactory<*>) : LocalQuickFix { + override fun getName() = "$familyName with ${diagnosticFactory.name}" + + override fun getFamilyName() = "Replace diagnostic name" + + override fun applyFix(project: Project, descriptor: ProblemDescriptor) { + val expression = descriptor.psiElement as? KtStringTemplateExpression ?: return + if (!FileModificationService.getInstance().preparePsiElementForWrite(expression)) return + + val psiFactory = KtPsiFactory(expression) + expression.replace(psiFactory.createExpression("\"${diagnosticFactory.name}\"")) + } + + } + + companion object { + + private val MIGRATION_MAP = mapOf( + "HEADER_DECLARATION_WITH_BODY" to EXPECTED_DECLARATION_WITH_BODY, + "HEADER_DECLARATION_WITH_DEFAULT_PARAMETER" to EXPECTED_DECLARATION_WITH_DEFAULT_PARAMETER, + "HEADER_CLASS_CONSTRUCTOR_DELEGATION_CALL" to EXPECTED_CLASS_CONSTRUCTOR_DELEGATION_CALL, + "HEADER_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER" to EXPECTED_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER, + "HEADER_ENUM_CONSTRUCTOR" to EXPECTED_ENUM_CONSTRUCTOR, + "HEADER_ENUM_ENTRY_WITH_BODY" to EXPECTED_ENUM_ENTRY_WITH_BODY, + "HEADER_PROPERTY_INITIALIZER" to EXPECTED_PROPERTY_INITIALIZER, + + "IMPL_TYPE_ALIAS_NOT_TO_CLASS" to ACTUAL_TYPE_ALIAS_NOT_TO_CLASS, + "IMPL_TYPE_ALIAS_TO_CLASS_WITH_DECLARATION_SITE_VARIANCE" to ACTUAL_TYPE_ALIAS_TO_CLASS_WITH_DECLARATION_SITE_VARIANCE, + "IMPL_TYPE_ALIAS_WITH_USE_SITE_VARIANCE" to ACTUAL_TYPE_ALIAS_WITH_USE_SITE_VARIANCE, + "IMPL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION" to ACTUAL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION, + + "HEADER_WITHOUT_IMPLEMENTATION" to NO_ACTUAL_FOR_EXPECT, + "IMPLEMENTATION_WITHOUT_HEADER" to ACTUAL_WITHOUT_EXPECT, + + "HEADER_CLASS_MEMBERS_ARE_NOT_IMPLEMENTED" to NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS, + "IMPL_MISSING" to ACTUAL_MISSING + ) + } +} diff --git a/idea/testData/inspectionsLocal/migrateDiagnosticSuppression/.inspection b/idea/testData/inspectionsLocal/migrateDiagnosticSuppression/.inspection new file mode 100644 index 00000000000..126a7575ae8 --- /dev/null +++ b/idea/testData/inspectionsLocal/migrateDiagnosticSuppression/.inspection @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.inspections.MigrateDiagnosticSuppressionInspection diff --git a/idea/testData/inspectionsLocal/migrateDiagnosticSuppression/base.kt b/idea/testData/inspectionsLocal/migrateDiagnosticSuppression/base.kt new file mode 100644 index 00000000000..133ebf98310 --- /dev/null +++ b/idea/testData/inspectionsLocal/migrateDiagnosticSuppression/base.kt @@ -0,0 +1,2 @@ +@Suppress("HEADER_WITHOUT_IMPLEMENTATION") +class Dummy \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/migrateDiagnosticSuppression/base.kt.after b/idea/testData/inspectionsLocal/migrateDiagnosticSuppression/base.kt.after new file mode 100644 index 00000000000..65c720f79b2 --- /dev/null +++ b/idea/testData/inspectionsLocal/migrateDiagnosticSuppression/base.kt.after @@ -0,0 +1,2 @@ +@Suppress("NO_ACTUAL_FOR_EXPECT") +class Dummy \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/migrateDiagnosticSuppression/multiple.kt b/idea/testData/inspectionsLocal/migrateDiagnosticSuppression/multiple.kt new file mode 100644 index 00000000000..04783a4535e --- /dev/null +++ b/idea/testData/inspectionsLocal/migrateDiagnosticSuppression/multiple.kt @@ -0,0 +1,6 @@ +@Suppress( + "HEADER_CLASS_CONSTRUCTOR_DELEGATION_CALL", + "HEADER_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER", + "HEADER_ENUM_CONSTRUCTOR" +) +class Dummy \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/migrateDiagnosticSuppression/multiple.kt.after b/idea/testData/inspectionsLocal/migrateDiagnosticSuppression/multiple.kt.after new file mode 100644 index 00000000000..03acd40338f --- /dev/null +++ b/idea/testData/inspectionsLocal/migrateDiagnosticSuppression/multiple.kt.after @@ -0,0 +1,6 @@ +@Suppress( + "HEADER_CLASS_CONSTRUCTOR_DELEGATION_CALL", + "EXPECTED_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER", + "HEADER_ENUM_CONSTRUCTOR" +) +class Dummy \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/migrateDiagnosticSuppression/new.kt b/idea/testData/inspectionsLocal/migrateDiagnosticSuppression/new.kt new file mode 100644 index 00000000000..25d477acbe3 --- /dev/null +++ b/idea/testData/inspectionsLocal/migrateDiagnosticSuppression/new.kt @@ -0,0 +1,4 @@ +// PROBLEM: none + +@Suppress("NO_ACTUAL_FOR_EXPECT") +class Dummy \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index 3d3562ed4cb..f78b909e7b3 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -1071,6 +1071,33 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { } } + @TestMetadata("idea/testData/inspectionsLocal/migrateDiagnosticSuppression") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class MigrateDiagnosticSuppression extends AbstractLocalInspectionTest { + public void testAllFilesPresentInMigrateDiagnosticSuppression() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/migrateDiagnosticSuppression"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("base.kt") + public void testBase() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/migrateDiagnosticSuppression/base.kt"); + doTest(fileName); + } + + @TestMetadata("multiple.kt") + public void testMultiple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/migrateDiagnosticSuppression/multiple.kt"); + doTest(fileName); + } + + @TestMetadata("new.kt") + public void testNew() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/migrateDiagnosticSuppression/new.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/inspectionsLocal/moveSuspiciousCallableReferenceIntoParentheses") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)