Supported default objects in unused symbol inspection.

This commit is contained in:
Evgeny Gerashchenko
2015-03-11 23:39:24 +03:00
parent 70a925317a
commit c875584d0c
7 changed files with 129 additions and 78 deletions
@@ -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
@@ -1,23 +0,0 @@
package defaultObject
class A {
default object {
}
}
class B {
default object NamedUnused {
}
}
class C {
default object NamedUsed {
}
}
fun main(args: Array<String>) {
A()
B()
C()
C.NamedUsed
}
@@ -0,0 +1,14 @@
class A {
default object {
}
}
class B {
default object Named {
}
}
fun main(args: Array<String>) {
A()
B()
}
@@ -0,0 +1,14 @@
class A {
default object {
}
}
class B {
default object Named {
}
}
fun main(args: Array<String>) {
val a = A
B.Named
}
@@ -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();
}
}
@@ -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() {
}
}
}
@@ -31,4 +31,22 @@
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Unused Symbol</problem_class>
<description>Object 'A' is never used</description>
</problem>
<problem>
<file>defaultObjectUnused.kt</file>
<line>2</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/defaultObjectUnused.kt" />
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Unused Symbol</problem_class>
<description>Object 'Default' is never used</description>
</problem>
<problem>
<file>defaultObjectUnused.kt</file>
<line>7</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/defaultObjectUnused.kt" />
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Unused Symbol</problem_class>
<description>Object 'Named' is never used</description>
</problem>
</problems>