From c875584d0cfbaa112b001a603bd2e41bcb1c06c0 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Wed, 11 Mar 2015 23:39:24 +0300 Subject: [PATCH] Supported default objects in unused symbol inspection. --- .../inspections/UnusedSymbolInspection.kt | 100 ++++++++---------- .../unusedSymbol/object/defaultObject.kt | 23 ---- .../object/defaultObjectUnused.kt | 14 +++ .../unusedSymbol/object/defaultObjectUsed.kt | 14 +++ .../object/defaultObjectUsedInJava.java | 9 ++ .../object/defaultObjectUsedInJava.kt | 29 +++++ .../object/inspectionData/expected.xml | 18 ++++ 7 files changed, 129 insertions(+), 78 deletions(-) delete mode 100644 idea/testData/inspections/unusedSymbol/object/defaultObject.kt create mode 100644 idea/testData/inspections/unusedSymbol/object/defaultObjectUnused.kt create mode 100644 idea/testData/inspections/unusedSymbol/object/defaultObjectUsed.kt create mode 100644 idea/testData/inspections/unusedSymbol/object/defaultObjectUsedInJava.java create mode 100644 idea/testData/inspections/unusedSymbol/object/defaultObjectUsedInJava.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt index 4cd8b00d8e9..bd7f5d73423 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt @@ -16,60 +16,40 @@ package org.jetbrains.kotlin.idea.inspections -import org.jetbrains.kotlin.psi.psiUtil.isAncestor -import com.intellij.codeInspection.ProblemsHolder -import com.intellij.codeInspection.LocalInspectionToolSession -import com.intellij.psi.PsiElementVisitor -import org.jetbrains.kotlin.psi.JetVisitorVoid -import org.jetbrains.kotlin.psi.JetClass -import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearchTarget -import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearch -import org.jetbrains.kotlin.idea.JetBundle -import com.intellij.codeInspection.ProblemHighlightType -import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection -import org.jetbrains.kotlin.asJava.LightClassUtil -import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindClassUsagesHandler -import com.intellij.psi.search.GlobalSearchScope -import org.jetbrains.kotlin.psi.JetNamedDeclaration -import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesHandlerFactory -import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.lexer.JetTokens -import org.jetbrains.kotlin.psi.JetNamedFunction -import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearchHelper -import org.jetbrains.kotlin.idea.search.usagesSearch.ClassUsagesSearchHelper -import org.jetbrains.kotlin.asJava.toLightClass -import org.jetbrains.kotlin.idea.search.usagesSearch.FunctionUsagesSearchHelper -import com.intellij.psi.search.PsiSearchHelper -import com.intellij.psi.search.PsiSearchHelper.SearchCostResult.* -import org.jetbrains.kotlin.idea.search.usagesSearch.getOperationSymbolsToSearch -import org.jetbrains.kotlin.idea.search.usagesSearch.INVOKE_OPERATION_NAME -import org.jetbrains.kotlin.psi.JetEnumEntry -import org.jetbrains.kotlin.psi.JetProperty -import org.jetbrains.kotlin.idea.search.usagesSearch.PropertyUsagesSearchHelper -import org.jetbrains.kotlin.idea.search.usagesSearch.getAccessorNames -import org.jetbrains.kotlin.psi.JetParameter -import org.jetbrains.kotlin.idea.search.usagesSearch.dataClassComponentFunctionName -import org.jetbrains.kotlin.psi.JetTypeParameter -import org.jetbrains.kotlin.idea.search.usagesSearch.DefaultSearchHelper -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 -import org.jetbrains.kotlin.psi.JetPsiUtil -import org.jetbrains.kotlin.psi.JetObjectDeclaration -import org.jetbrains.kotlin.psi.JetClassOrObject -import org.jetbrains.kotlin.idea.util.ProjectRootsUtil -import org.jetbrains.kotlin.idea.project.ProjectStructureUtil -import javax.swing.JComponent -import java.awt.GridBagConstraints -import java.awt.Insets +import com.intellij.codeInsight.daemon.QuickFixBundle +import com.intellij.codeInspection.* +import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection import com.intellij.codeInspection.ex.EntryPointsManager import com.intellij.codeInspection.ex.EntryPointsManagerImpl +import com.intellij.openapi.project.Project import com.intellij.openapi.project.ProjectUtil +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiElementVisitor +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.search.PsiSearchHelper +import com.intellij.psi.search.PsiSearchHelper.SearchCostResult.FEW_OCCURRENCES +import com.intellij.psi.search.PsiSearchHelper.SearchCostResult.TOO_MANY_OCCURRENCES +import com.intellij.psi.search.PsiSearchHelper.SearchCostResult.ZERO_OCCURRENCES +import com.intellij.refactoring.safeDelete.SafeDeleteHandler +import com.intellij.util.Processor +import org.jetbrains.kotlin.asJava.LightClassUtil +import org.jetbrains.kotlin.asJava.toLightClass +import org.jetbrains.kotlin.idea.JetBundle +import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesHandlerFactory +import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindClassUsagesHandler +import org.jetbrains.kotlin.idea.project.ProjectStructureUtil +import org.jetbrains.kotlin.idea.search.usagesSearch.* +import org.jetbrains.kotlin.idea.util.ProjectRootsUtil +import org.jetbrains.kotlin.lexer.JetTokens +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.isAncestor +import org.jetbrains.kotlin.utils.singletonOrEmptyList +import java.awt.GridBagConstraints import java.awt.GridBagLayout +import java.awt.Insets +import javax.swing.JComponent import javax.swing.JPanel public class UnusedSymbolInspection : AbstractKotlinInspection() { @@ -121,14 +101,13 @@ public class UnusedSymbolInspection : AbstractKotlinInspection() { if (!ProjectRootsUtil.isInProjectSource(declaration)) return // Simple PSI-based checks - if (declaration.getNameIdentifier() == null) return + val isDefaultObject = declaration is JetObjectDeclaration && declaration.isDefault() + if (declaration.getNameIdentifier() == null && !isDefaultObject) return if (declaration is JetEnumEntry) return if (declaration.hasModifier(JetTokens.OVERRIDE_KEYWORD)) return if (declaration is JetProperty && declaration.isLocal()) return if (declaration is JetParameter && (declaration.getParent()?.getParent() !is JetClass || !declaration.hasValOrVarNode())) return if (declaration is JetNamedFunction && isConventionalName(declaration)) return - //TODO: support this inspection for default objects - if (declaration is JetObjectDeclaration && declaration.isDefault()) return // More expensive, resolve-based checks if (isEntryPoint(declaration)) return @@ -139,12 +118,23 @@ public class UnusedSymbolInspection : AbstractKotlinInspection() { if (hasNonTrivialUsages(declaration)) return if (declaration is JetClassOrObject && classOrObjectHasTextUsages(declaration)) return - holder.registerProblem( - declaration.getNameIdentifier(), + val (inspectionTarget, textRange) = if (isDefaultObject && declaration.getNameIdentifier() == null) { + val objectKeyword = (declaration as JetObjectDeclaration).getObjectKeyword() + Pair(declaration, TextRange(0, objectKeyword.getStartOffsetInParent() + objectKeyword.getTextLength())) + } else { + Pair(declaration.getNameIdentifier()!!, null) + } + + val problemDescriptor = holder.getManager().createProblemDescriptor( + inspectionTarget, + textRange, JetBundle.message(messageKey, declaration.getName()), ProblemHighlightType.LIKE_UNUSED_SYMBOL, + true, createQuickFix(declaration) ) + + holder.registerProblem(problemDescriptor) } } } @@ -177,7 +167,7 @@ public class UnusedSymbolInspection : AbstractKotlinInspection() { if (useScope is GlobalSearchScope) { var zeroOccurrences = true - for (name in listOf(declaration.getName()) + declaration.getAccessorNames()) { + for (name in listOf(declaration.getName()) + declaration.getAccessorNames() + declaration.getClassNameForDefaultObject().singletonOrEmptyList()) { when (psiSearchHelper.isCheapEnoughToSearch(name, useScope, null, null)) { ZERO_OCCURRENCES -> {} // go on, check other names FEW_OCCURRENCES -> zeroOccurrences = false diff --git a/idea/testData/inspections/unusedSymbol/object/defaultObject.kt b/idea/testData/inspections/unusedSymbol/object/defaultObject.kt deleted file mode 100644 index c7c89847fd1..00000000000 --- a/idea/testData/inspections/unusedSymbol/object/defaultObject.kt +++ /dev/null @@ -1,23 +0,0 @@ -package defaultObject - -class A { - default object { - } -} - -class B { - default object NamedUnused { - } -} - -class C { - default object NamedUsed { - } -} - -fun main(args: Array) { - A() - B() - C() - C.NamedUsed -} \ No newline at end of file diff --git a/idea/testData/inspections/unusedSymbol/object/defaultObjectUnused.kt b/idea/testData/inspections/unusedSymbol/object/defaultObjectUnused.kt new file mode 100644 index 00000000000..4140b1534ad --- /dev/null +++ b/idea/testData/inspections/unusedSymbol/object/defaultObjectUnused.kt @@ -0,0 +1,14 @@ +class A { + default object { + } +} + +class B { + default object Named { + } +} + +fun main(args: Array) { + A() + B() +} \ No newline at end of file diff --git a/idea/testData/inspections/unusedSymbol/object/defaultObjectUsed.kt b/idea/testData/inspections/unusedSymbol/object/defaultObjectUsed.kt new file mode 100644 index 00000000000..01aa9da1541 --- /dev/null +++ b/idea/testData/inspections/unusedSymbol/object/defaultObjectUsed.kt @@ -0,0 +1,14 @@ +class A { + default object { + } +} + +class B { + default object Named { + } +} + +fun main(args: Array) { + val a = A + B.Named +} \ No newline at end of file diff --git a/idea/testData/inspections/unusedSymbol/object/defaultObjectUsedInJava.java b/idea/testData/inspections/unusedSymbol/object/defaultObjectUsedInJava.java new file mode 100644 index 00000000000..cf56bad1a80 --- /dev/null +++ b/idea/testData/inspections/unusedSymbol/object/defaultObjectUsedInJava.java @@ -0,0 +1,9 @@ +import defaultObjectUsedInJava.* + +class JavaUsage { + public static void main(String[] args) { + System.out.println(A.CONST + C.CONST); + B.foo(); + D.foo(); + } +} \ No newline at end of file diff --git a/idea/testData/inspections/unusedSymbol/object/defaultObjectUsedInJava.kt b/idea/testData/inspections/unusedSymbol/object/defaultObjectUsedInJava.kt new file mode 100644 index 00000000000..1cc7e0a92db --- /dev/null +++ b/idea/testData/inspections/unusedSymbol/object/defaultObjectUsedInJava.kt @@ -0,0 +1,29 @@ +package defaultObjectUsedInJava + +import kotlin.platform.platformStatic + +class A { + default object { + val CONST = 42 + } +} + +class B { + default object { + platformStatic fun foo() { + } + } +} + +class C { + default object Named { + val CONST = 42 + } +} + +class D { + default object Named { + platformStatic fun foo() { + } + } +} diff --git a/idea/testData/inspections/unusedSymbol/object/inspectionData/expected.xml b/idea/testData/inspections/unusedSymbol/object/inspectionData/expected.xml index 83fca7a2830..8984a4be145 100644 --- a/idea/testData/inspections/unusedSymbol/object/inspectionData/expected.xml +++ b/idea/testData/inspections/unusedSymbol/object/inspectionData/expected.xml @@ -31,4 +31,22 @@ Unused Symbol Object 'A' is never used + + + defaultObjectUnused.kt + 2 + light_idea_test_case + + Unused Symbol + Object 'Default' is never used + + + + defaultObjectUnused.kt + 7 + light_idea_test_case + + Unused Symbol + Object 'Named' is never used +