From 8a21275a2fa476a7881de32bbc1d4f45a58a2930 Mon Sep 17 00:00:00 2001 From: Alexander Perfilyev Date: Sat, 10 Apr 2021 01:20:11 +0300 Subject: [PATCH] Add unused import inspection (#2263) closes #1161 --- .../sqldelight/core/lang/util/TreeUtil.kt | 4 ++ .../inspections/UnusedImportInspection.kt | 54 +++++++++++++++++++ .../lang/SqlDelightImportOptimizer.kt | 44 +++++++++++++++ .../src/main/resources/META-INF/plugin.xml | 12 +++++ .../inspections/UnusedImportInspectionTest.kt | 13 +++++ .../testData/inspections/expected.xml | 13 +++++ .../testData/inspections/src/AlterTable.sqm | 3 ++ .../testData/inspections/src/CreateTable.sq | 6 +++ 8 files changed, 149 insertions(+) create mode 100644 sqldelight-idea-plugin/src/main/kotlin/com/squareup/sqldelight/intellij/inspections/UnusedImportInspection.kt create mode 100644 sqldelight-idea-plugin/src/main/kotlin/com/squareup/sqldelight/intellij/lang/SqlDelightImportOptimizer.kt create mode 100644 sqldelight-idea-plugin/src/test/kotlin/com/squareup/sqldelight/intellij/inspections/UnusedImportInspectionTest.kt create mode 100644 sqldelight-idea-plugin/testData/inspections/expected.xml create mode 100644 sqldelight-idea-plugin/testData/inspections/src/AlterTable.sqm create mode 100644 sqldelight-idea-plugin/testData/inspections/src/CreateTable.sq diff --git a/sqldelight-compiler/src/main/kotlin/com/squareup/sqldelight/core/lang/util/TreeUtil.kt b/sqldelight-compiler/src/main/kotlin/com/squareup/sqldelight/core/lang/util/TreeUtil.kt index 7df7b1f959e..3a12ddf53a9 100644 --- a/sqldelight-compiler/src/main/kotlin/com/squareup/sqldelight/core/lang/util/TreeUtil.kt +++ b/sqldelight-compiler/src/main/kotlin/com/squareup/sqldelight/core/lang/util/TreeUtil.kt @@ -79,6 +79,10 @@ inline fun PsiElement.findChildrenOfType(): Collection< return PsiTreeUtil.findChildrenOfType(this, T::class.java) } +inline fun PsiElement.findChildOfType(): T? { + return PsiTreeUtil.findChildOfType(this, T::class.java) +} + fun PsiElement.childOfType(type: IElementType): PsiElement? { return node.findChildByType(type)?.psi } diff --git a/sqldelight-idea-plugin/src/main/kotlin/com/squareup/sqldelight/intellij/inspections/UnusedImportInspection.kt b/sqldelight-idea-plugin/src/main/kotlin/com/squareup/sqldelight/intellij/inspections/UnusedImportInspection.kt new file mode 100644 index 00000000000..a6c685aad0e --- /dev/null +++ b/sqldelight-idea-plugin/src/main/kotlin/com/squareup/sqldelight/intellij/inspections/UnusedImportInspection.kt @@ -0,0 +1,54 @@ +package com.squareup.sqldelight.intellij.inspections + +import com.intellij.codeInsight.actions.OptimizeImportsProcessor +import com.intellij.codeInspection.InspectionManager +import com.intellij.codeInspection.LocalInspectionTool +import com.intellij.codeInspection.LocalQuickFixOnPsiElement +import com.intellij.codeInspection.ProblemDescriptor +import com.intellij.codeInspection.ProblemHighlightType +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.squareup.sqldelight.core.lang.psi.ImportStmtMixin +import com.squareup.sqldelight.core.lang.util.findChildrenOfType +import com.squareup.sqldelight.core.psi.SqlDelightJavaTypeName + +class UnusedImportInspection : LocalInspectionTool() { + + override fun runForWholeFile(): Boolean = true + + override fun checkFile( + file: PsiFile, + manager: InspectionManager, + isOnTheFly: Boolean + ): Array { + val columnTypes = file.findChildrenOfType() + .map { javaTypeName -> javaTypeName.text } + + return file.findChildrenOfType() + .filter { importStmtMixin -> importStmtMixin.text.findAnyOf(columnTypes) == null } + .map { importStmtMixin -> + manager.createProblemDescriptor( + importStmtMixin, "Unused import", isOnTheFly, + arrayOf(RemoveUnusedImportQuickFix(file)), ProblemHighlightType.LIKE_UNUSED_SYMBOL + ) + } + .toTypedArray() + } + + class RemoveUnusedImportQuickFix(file: PsiFile) : LocalQuickFixOnPsiElement(file) { + + override fun getFamilyName(): String = name + + override fun getText(): String = "Optimize imports" + + override fun invoke( + project: Project, + file: PsiFile, + startElement: PsiElement, + endElement: PsiElement + ) { + OptimizeImportsProcessor(project, file).run() + } + } +} diff --git a/sqldelight-idea-plugin/src/main/kotlin/com/squareup/sqldelight/intellij/lang/SqlDelightImportOptimizer.kt b/sqldelight-idea-plugin/src/main/kotlin/com/squareup/sqldelight/intellij/lang/SqlDelightImportOptimizer.kt new file mode 100644 index 00000000000..855a11c564d --- /dev/null +++ b/sqldelight-idea-plugin/src/main/kotlin/com/squareup/sqldelight/intellij/lang/SqlDelightImportOptimizer.kt @@ -0,0 +1,44 @@ +package com.squareup.sqldelight.intellij.lang + +import com.intellij.lang.ImportOptimizer +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiFileFactory +import com.squareup.sqldelight.core.lang.MigrationFile +import com.squareup.sqldelight.core.lang.SqlDelightFile +import com.squareup.sqldelight.core.lang.SqlDelightFileType +import com.squareup.sqldelight.core.lang.psi.ImportStmtMixin +import com.squareup.sqldelight.core.lang.util.findChildOfType +import com.squareup.sqldelight.core.lang.util.findChildrenOfType +import com.squareup.sqldelight.core.psi.SqlDelightImportStmtList +import com.squareup.sqldelight.core.psi.SqlDelightJavaTypeName + +class SqlDelightImportOptimizer : ImportOptimizer { + + override fun supports(file: PsiFile): Boolean = file is SqlDelightFile || file is MigrationFile + + override fun processFile(file: PsiFile): Runnable = Runnable { + val manager = PsiDocumentManager.getInstance(file.project) + val document = manager.getDocument(file) ?: return@Runnable + manager.commitDocument(document) + + val columnTypes = file.findChildrenOfType() + .map { javaTypeName -> javaTypeName.text } + + val remainingImports = file.findChildrenOfType() + .asSequence() + .map { import -> import.text } + .filter { import -> import.findAnyOf(columnTypes) != null } + .sorted() + .joinToString("\n") + val factory = PsiFileFactory.getInstance(file.project) + val dummyFile = factory.createFileFromText( + "_Dummy_.${SqlDelightFileType.EXTENSION}", + SqlDelightFileType, remainingImports + ) + val newImportList = dummyFile.findChildOfType() + if (newImportList != null) { + file.findChildOfType()?.replace(newImportList) + } + } +} diff --git a/sqldelight-idea-plugin/src/main/resources/META-INF/plugin.xml b/sqldelight-idea-plugin/src/main/resources/META-INF/plugin.xml index ee61cf8ab59..9f01bef1285 100644 --- a/sqldelight-idea-plugin/src/main/resources/META-INF/plugin.xml +++ b/sqldelight-idea-plugin/src/main/resources/META-INF/plugin.xml @@ -100,10 +100,22 @@ + + + + com.squareup.sqldelight.intellij.intentions.ExpandColumnNamesWildcardQuickFix SQLDelight + + diff --git a/sqldelight-idea-plugin/src/test/kotlin/com/squareup/sqldelight/intellij/inspections/UnusedImportInspectionTest.kt b/sqldelight-idea-plugin/src/test/kotlin/com/squareup/sqldelight/intellij/inspections/UnusedImportInspectionTest.kt new file mode 100644 index 00000000000..b121f0b3612 --- /dev/null +++ b/sqldelight-idea-plugin/src/test/kotlin/com/squareup/sqldelight/intellij/inspections/UnusedImportInspectionTest.kt @@ -0,0 +1,13 @@ +package com.squareup.sqldelight.intellij.inspections + +import com.intellij.codeInspection.ex.LocalInspectionToolWrapper +import com.squareup.sqldelight.intellij.SqlDelightFixtureTestCase + +class UnusedImportInspectionTest : SqlDelightFixtureTestCase() { + + override val fixtureDirectory: String = "inspections" + + fun testUnusedImportInspection() { + myFixture.testInspection("", LocalInspectionToolWrapper(UnusedImportInspection())) + } +} diff --git a/sqldelight-idea-plugin/testData/inspections/expected.xml b/sqldelight-idea-plugin/testData/inspections/expected.xml new file mode 100644 index 00000000000..17ca37f0d0a --- /dev/null +++ b/sqldelight-idea-plugin/testData/inspections/expected.xml @@ -0,0 +1,13 @@ + + + + CreateTable.sq + 1 + Unused import + + + AlterTable.sqm + 1 + Unused import + + \ No newline at end of file diff --git a/sqldelight-idea-plugin/testData/inspections/src/AlterTable.sqm b/sqldelight-idea-plugin/testData/inspections/src/AlterTable.sqm new file mode 100644 index 00000000000..ed61a3af119 --- /dev/null +++ b/sqldelight-idea-plugin/testData/inspections/src/AlterTable.sqm @@ -0,0 +1,3 @@ +import java.time.OffsetDateTime; + +ALTER TABLE hockeyPlayer ADD COLUMN draft_year TEXT; \ No newline at end of file diff --git a/sqldelight-idea-plugin/testData/inspections/src/CreateTable.sq b/sqldelight-idea-plugin/testData/inspections/src/CreateTable.sq new file mode 100644 index 00000000000..2ed7fa9be72 --- /dev/null +++ b/sqldelight-idea-plugin/testData/inspections/src/CreateTable.sq @@ -0,0 +1,6 @@ +import java.time.OffsetDateTime; + +CREATE TABLE hockeyPlayer ( + player_number INTEGER NOT NULL, + full_name TEXT NOT NULL +); \ No newline at end of file