Quick fix for unused symbol inspection.
This commit is contained in:
@@ -52,6 +52,12 @@ import org.jetbrains.kotlin.idea.search.usagesSearch.dataClassComponentFunctionN
|
|||||||
import org.jetbrains.kotlin.psi.JetTypeParameter
|
import org.jetbrains.kotlin.psi.JetTypeParameter
|
||||||
import org.jetbrains.kotlin.idea.search.usagesSearch.DefaultSearchHelper
|
import org.jetbrains.kotlin.idea.search.usagesSearch.DefaultSearchHelper
|
||||||
import com.intellij.util.Processor
|
import com.intellij.util.Processor
|
||||||
|
import com.intellij.codeInspection.LocalQuickFix
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.codeInspection.ProblemDescriptor
|
||||||
|
import com.intellij.codeInsight.daemon.QuickFixBundle
|
||||||
|
import com.intellij.codeInsight.FileModificationService
|
||||||
|
import com.intellij.refactoring.safeDelete.SafeDeleteHandler
|
||||||
|
|
||||||
public class UnusedSymbolInspection : AbstractKotlinInspection() {
|
public class UnusedSymbolInspection : AbstractKotlinInspection() {
|
||||||
private val javaInspection = UnusedDeclarationInspection()
|
private val javaInspection = UnusedDeclarationInspection()
|
||||||
@@ -60,6 +66,19 @@ public class UnusedSymbolInspection : AbstractKotlinInspection() {
|
|||||||
|
|
||||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
|
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
|
||||||
return object : JetVisitorVoid() {
|
return object : JetVisitorVoid() {
|
||||||
|
private fun createQuickFix(declaration: JetNamedDeclaration): LocalQuickFix {
|
||||||
|
return object : LocalQuickFix {
|
||||||
|
override fun getName() = QuickFixBundle.message("safe.delete.text", declaration.getName())
|
||||||
|
|
||||||
|
override fun getFamilyName() = "whatever"
|
||||||
|
|
||||||
|
override fun applyFix(project: Project, descriptor: ProblemDescriptor?) {
|
||||||
|
if (!FileModificationService.getInstance().prepareFileForWrite(declaration.getContainingFile())) return
|
||||||
|
SafeDeleteHandler.invoke(project, array(declaration), false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitClass(klass: JetClass) {
|
override fun visitClass(klass: JetClass) {
|
||||||
if (klass.getName() == null) return
|
if (klass.getName() == null) return
|
||||||
|
|
||||||
@@ -72,8 +91,9 @@ public class UnusedSymbolInspection : AbstractKotlinInspection() {
|
|||||||
holder.registerProblem(
|
holder.registerProblem(
|
||||||
klass.getNameIdentifier(),
|
klass.getNameIdentifier(),
|
||||||
JetBundle.message("unused.class", klass.getName()),
|
JetBundle.message("unused.class", klass.getName()),
|
||||||
ProblemHighlightType.LIKE_UNUSED_SYMBOL
|
ProblemHighlightType.LIKE_UNUSED_SYMBOL,
|
||||||
) // TODO add quick fix to delete it
|
createQuickFix(klass)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitNamedFunction(function: JetNamedFunction) {
|
override fun visitNamedFunction(function: JetNamedFunction) {
|
||||||
@@ -87,8 +107,9 @@ public class UnusedSymbolInspection : AbstractKotlinInspection() {
|
|||||||
holder.registerProblem(
|
holder.registerProblem(
|
||||||
function.getNameIdentifier(),
|
function.getNameIdentifier(),
|
||||||
JetBundle.message("unused.function", function.getName()),
|
JetBundle.message("unused.function", function.getName()),
|
||||||
ProblemHighlightType.LIKE_UNUSED_SYMBOL
|
ProblemHighlightType.LIKE_UNUSED_SYMBOL,
|
||||||
) // TODO add quick fix to delete it
|
createQuickFix(function)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitProperty(property: JetProperty) {
|
override fun visitProperty(property: JetProperty) {
|
||||||
@@ -102,8 +123,9 @@ public class UnusedSymbolInspection : AbstractKotlinInspection() {
|
|||||||
holder.registerProblem(
|
holder.registerProblem(
|
||||||
property.getNameIdentifier(),
|
property.getNameIdentifier(),
|
||||||
JetBundle.message("unused.property", property.getName()),
|
JetBundle.message("unused.property", property.getName()),
|
||||||
ProblemHighlightType.LIKE_UNUSED_SYMBOL
|
ProblemHighlightType.LIKE_UNUSED_SYMBOL,
|
||||||
) // TODO add quick fix to delete it
|
createQuickFix(property)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitParameter(parameter: JetParameter) {
|
override fun visitParameter(parameter: JetParameter) {
|
||||||
@@ -120,8 +142,9 @@ public class UnusedSymbolInspection : AbstractKotlinInspection() {
|
|||||||
holder.registerProblem(
|
holder.registerProblem(
|
||||||
parameter.getNameIdentifier(),
|
parameter.getNameIdentifier(),
|
||||||
JetBundle.message("unused.property", parameter.getName()),
|
JetBundle.message("unused.property", parameter.getName()),
|
||||||
ProblemHighlightType.LIKE_UNUSED_SYMBOL
|
ProblemHighlightType.LIKE_UNUSED_SYMBOL,
|
||||||
) // TODO add quick fix to delete it
|
createQuickFix(parameter)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitTypeParameter(parameter: JetTypeParameter) {
|
override fun visitTypeParameter(parameter: JetTypeParameter) {
|
||||||
@@ -132,8 +155,9 @@ public class UnusedSymbolInspection : AbstractKotlinInspection() {
|
|||||||
holder.registerProblem(
|
holder.registerProblem(
|
||||||
parameter.getNameIdentifier(),
|
parameter.getNameIdentifier(),
|
||||||
JetBundle.message("unused.type.parameter", parameter.getName()),
|
JetBundle.message("unused.type.parameter", parameter.getName()),
|
||||||
ProblemHighlightType.LIKE_UNUSED_SYMBOL
|
ProblemHighlightType.LIKE_UNUSED_SYMBOL,
|
||||||
) // TODO add quick fix to delete it
|
createQuickFix(parameter)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,4 +224,4 @@ public class UnusedSymbolInspection : AbstractKotlinInspection() {
|
|||||||
|
|
||||||
return !query.forEach(Processor { declaration.isAncestor(it.getElement()) })
|
return !query.forEach(Processor { declaration.isAncestor(it.getElement()) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
org.jetbrains.kotlin.idea.inspections.UnusedSymbolInspection
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
// "Safe delete 'UnusedClass'" "true"
|
||||||
|
class DummyClass
|
||||||
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// "Safe delete 'unusedFun'" "true"
|
||||||
|
fun dummy() {
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
// "Safe delete 'property'" "true"
|
||||||
|
class UnusedProperty() {
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
// "Safe delete 'property'" "true"
|
||||||
|
class UnusedPropertyAsConstructorParameter()
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
// "Safe delete 'T'" "true"
|
||||||
|
class UnusedTypeParameter<P>(val p: P)
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// "Safe delete 'UnusedClass'" "true"
|
||||||
|
class DummyClass
|
||||||
|
|
||||||
|
class <caret>UnusedClass
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// "Safe delete 'unusedFun'" "true"
|
||||||
|
fun dummy() {
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <caret>unusedFun() {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// "Safe delete 'property'" "true"
|
||||||
|
class UnusedProperty() {
|
||||||
|
val <caret>property: String = ":)"
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
// "Safe delete 'property'" "true"
|
||||||
|
class UnusedPropertyAsConstructorParameter(val <caret>property: String)
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
// "Safe delete 'T'" "true"
|
||||||
|
class UnusedTypeParameter<<caret>T, P>(val p: P)
|
||||||
@@ -26,9 +26,11 @@ import com.intellij.openapi.projectRoots.JavaSdk;
|
|||||||
import com.intellij.openapi.projectRoots.Sdk;
|
import com.intellij.openapi.projectRoots.Sdk;
|
||||||
import com.intellij.openapi.startup.StartupManager;
|
import com.intellij.openapi.startup.StartupManager;
|
||||||
import com.intellij.openapi.util.Pair;
|
import com.intellij.openapi.util.Pair;
|
||||||
|
import com.intellij.openapi.util.io.FileUtil;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import org.apache.commons.lang.SystemUtils;
|
import org.apache.commons.lang.SystemUtils;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.idea.DirectiveBasedActionUtils;
|
import org.jetbrains.kotlin.idea.DirectiveBasedActionUtils;
|
||||||
import org.jetbrains.kotlin.idea.KotlinLightQuickFixTestCase;
|
import org.jetbrains.kotlin.idea.KotlinLightQuickFixTestCase;
|
||||||
import org.jetbrains.kotlin.idea.PluginTestCaseBase;
|
import org.jetbrains.kotlin.idea.PluginTestCaseBase;
|
||||||
@@ -39,6 +41,7 @@ import org.jetbrains.kotlin.test.TestMetadata;
|
|||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -50,6 +53,19 @@ public abstract class AbstractQuickFixTest extends KotlinLightQuickFixTestCase {
|
|||||||
((StartupManagerImpl) StartupManager.getInstance(getProject())).runPostStartupActivities();
|
((StartupManagerImpl) StartupManager.getInstance(getProject())).runPostStartupActivities();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static File findInspectionFile(@NotNull File startDir) {
|
||||||
|
File currentDir = startDir;
|
||||||
|
while (currentDir != null) {
|
||||||
|
File inspectionFile = new File(currentDir, ".inspection");
|
||||||
|
if (inspectionFile.exists()) {
|
||||||
|
return inspectionFile;
|
||||||
|
}
|
||||||
|
currentDir = currentDir.getParentFile();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
protected void doTest(@NotNull String beforeFileName) throws Exception {
|
protected void doTest(@NotNull String beforeFileName) throws Exception {
|
||||||
boolean isWithRuntime = beforeFileName.endsWith("Runtime.kt");
|
boolean isWithRuntime = beforeFileName.endsWith("Runtime.kt");
|
||||||
|
|
||||||
@@ -58,6 +74,8 @@ public abstract class AbstractQuickFixTest extends KotlinLightQuickFixTestCase {
|
|||||||
ConfigLibraryUtil.configureKotlinRuntime(getModule(), getFullJavaJDK());
|
ConfigLibraryUtil.configureKotlinRuntime(getModule(), getFullJavaJDK());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enableInspections(beforeFileName);
|
||||||
|
|
||||||
doSingleTest(getTestName(false) + ".kt");
|
doSingleTest(getTestName(false) + ".kt");
|
||||||
checkForUnexpectedActions();
|
checkForUnexpectedActions();
|
||||||
checkForUnexpectedErrors();
|
checkForUnexpectedErrors();
|
||||||
@@ -69,6 +87,15 @@ public abstract class AbstractQuickFixTest extends KotlinLightQuickFixTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void enableInspections(String beforeFileName) throws IOException, ClassNotFoundException {
|
||||||
|
File inspectionFile = findInspectionFile(new File(beforeFileName).getParentFile());
|
||||||
|
if (inspectionFile != null) {
|
||||||
|
String className = FileUtil.loadFile(inspectionFile).trim();
|
||||||
|
Class<?> inspectionClass = Class.forName(className);
|
||||||
|
enableInspectionTools(inspectionClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void checkForUnexpectedActions() throws ClassNotFoundException {
|
private void checkForUnexpectedActions() throws ClassNotFoundException {
|
||||||
String text = getEditor().getDocument().getText();
|
String text = getEditor().getDocument().getText();
|
||||||
Pair<String, Boolean> pair = parseActionHintImpl(getFile(), text);
|
Pair<String, Boolean> pair = parseActionHintImpl(getFile(), text);
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import java.util.regex.Pattern;
|
|||||||
@SuppressWarnings("all")
|
@SuppressWarnings("all")
|
||||||
@TestMetadata("idea/testData/quickfix")
|
@TestMetadata("idea/testData/quickfix")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@InnerTestClasses({QuickFixTestGenerated.Abstract.class, QuickFixTestGenerated.AddStarProjections.class, QuickFixTestGenerated.AutoImports.class, QuickFixTestGenerated.ChangeSignature.class, QuickFixTestGenerated.CheckArguments.class, QuickFixTestGenerated.ConflictingImports.class, QuickFixTestGenerated.CreateFromUsage.class, QuickFixTestGenerated.Expressions.class, QuickFixTestGenerated.Migration.class, QuickFixTestGenerated.Modifiers.class, QuickFixTestGenerated.Nullables.class, QuickFixTestGenerated.Override.class, QuickFixTestGenerated.PlatformClasses.class, QuickFixTestGenerated.Supercalls.class, QuickFixTestGenerated.SupertypeInitialization.class, QuickFixTestGenerated.Suppress.class, QuickFixTestGenerated.TypeAddition.class, QuickFixTestGenerated.TypeImports.class, QuickFixTestGenerated.TypeMismatch.class, QuickFixTestGenerated.TypeProjection.class, QuickFixTestGenerated.Variables.class, QuickFixTestGenerated.When.class})
|
@InnerTestClasses({QuickFixTestGenerated.Abstract.class, QuickFixTestGenerated.AddStarProjections.class, QuickFixTestGenerated.AutoImports.class, QuickFixTestGenerated.ChangeSignature.class, QuickFixTestGenerated.CheckArguments.class, QuickFixTestGenerated.ConflictingImports.class, QuickFixTestGenerated.CreateFromUsage.class, QuickFixTestGenerated.Expressions.class, QuickFixTestGenerated.Migration.class, QuickFixTestGenerated.Modifiers.class, QuickFixTestGenerated.Nullables.class, QuickFixTestGenerated.Override.class, QuickFixTestGenerated.PlatformClasses.class, QuickFixTestGenerated.RemoveUnused.class, QuickFixTestGenerated.Supercalls.class, QuickFixTestGenerated.SupertypeInitialization.class, QuickFixTestGenerated.Suppress.class, QuickFixTestGenerated.TypeAddition.class, QuickFixTestGenerated.TypeImports.class, QuickFixTestGenerated.TypeMismatch.class, QuickFixTestGenerated.TypeProjection.class, QuickFixTestGenerated.Variables.class, QuickFixTestGenerated.When.class})
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||||
public void testAllFilesPresentInQuickfix() throws Exception {
|
public void testAllFilesPresentInQuickfix() throws Exception {
|
||||||
@@ -3423,6 +3423,45 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/quickfix/removeUnused")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class RemoveUnused extends AbstractQuickFixTest {
|
||||||
|
public void testAllFilesPresentInRemoveUnused() throws Exception {
|
||||||
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/removeUnused"), Pattern.compile("^before(\\w+)\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("beforeUnusedClass.kt")
|
||||||
|
public void testUnusedClass() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/removeUnused/beforeUnusedClass.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("beforeUnusedFunction.kt")
|
||||||
|
public void testUnusedFunction() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/removeUnused/beforeUnusedFunction.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("beforeUnusedProperty.kt")
|
||||||
|
public void testUnusedProperty() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/removeUnused/beforeUnusedProperty.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("beforeUnusedPropertyAsConstructorParameter.kt")
|
||||||
|
public void testUnusedPropertyAsConstructorParameter() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/removeUnused/beforeUnusedPropertyAsConstructorParameter.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("beforeUnusedTypeParameter.kt")
|
||||||
|
public void testUnusedTypeParameter() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/removeUnused/beforeUnusedTypeParameter.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/quickfix/supercalls")
|
@TestMetadata("idea/testData/quickfix/supercalls")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user