Finding unused functions.
This commit is contained in:
@@ -118,6 +118,7 @@ goto.super.property.chooser.title=Choose super property
|
|||||||
goto.super.class.chooser.title=Choose super class or interface
|
goto.super.class.chooser.title=Choose super class or interface
|
||||||
|
|
||||||
unused.class=Class ''{0}'' is never used
|
unused.class=Class ''{0}'' is never used
|
||||||
|
unused.function=Function ''{0}'' is never used
|
||||||
|
|
||||||
livetemplate.description.main=main() function
|
livetemplate.description.main=main() function
|
||||||
livetemplate.description.soutp=Prints function parameter names and values to System.out
|
livetemplate.description.soutp=Prints function parameter names and values to System.out
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearch
|
|||||||
import org.jetbrains.kotlin.idea.JetBundle
|
import org.jetbrains.kotlin.idea.JetBundle
|
||||||
import com.intellij.codeInspection.ProblemHighlightType
|
import com.intellij.codeInspection.ProblemHighlightType
|
||||||
import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection
|
import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection
|
||||||
|
import org.jetbrains.kotlin.asJava.LightClassUtil
|
||||||
import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindClassUsagesHandler
|
import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindClassUsagesHandler
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import org.jetbrains.kotlin.psi.JetNamedDeclaration
|
import org.jetbrains.kotlin.psi.JetNamedDeclaration
|
||||||
@@ -49,7 +50,7 @@ public class UnusedSymbolInspection : AbstractKotlinInspection() {
|
|||||||
override fun visitClass(klass: JetClass) {
|
override fun visitClass(klass: JetClass) {
|
||||||
if (klass.getName() == null) return
|
if (klass.getName() == null) return
|
||||||
|
|
||||||
if (classIsEntryPoint(klass)) return
|
if (isEntryPoint(klass)) return
|
||||||
if (hasNonTrivialUsages(klass)) return
|
if (hasNonTrivialUsages(klass)) return
|
||||||
if (classHasTextUsages(klass)) return
|
if (classHasTextUsages(klass)) return
|
||||||
|
|
||||||
@@ -59,13 +60,30 @@ public class UnusedSymbolInspection : AbstractKotlinInspection() {
|
|||||||
ProblemHighlightType.LIKE_UNUSED_SYMBOL
|
ProblemHighlightType.LIKE_UNUSED_SYMBOL
|
||||||
) // TODO add quick fix to delete it
|
) // TODO add quick fix to delete it
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitNamedFunction(function: JetNamedFunction) {
|
||||||
|
if (function.getName() == null) return
|
||||||
|
|
||||||
|
if (function.hasModifier(JetTokens.OVERRIDE_KEYWORD)) return
|
||||||
|
if (isEntryPoint(function)) return
|
||||||
|
if (hasNonTrivialUsages(function)) return
|
||||||
|
|
||||||
|
holder.registerProblem(
|
||||||
|
function.getNameIdentifier(),
|
||||||
|
JetBundle.message("unused.function", function.getName()),
|
||||||
|
ProblemHighlightType.LIKE_UNUSED_SYMBOL
|
||||||
|
) // TODO add quick fix to delete it
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun classIsEntryPoint(klass: JetClass): Boolean {
|
private fun isEntryPoint(declaration: JetNamedDeclaration): Boolean {
|
||||||
val lightClass = klass.toLightClass()
|
val lightElement: PsiElement? = when (declaration) {
|
||||||
if (lightClass != null && javaInspection.isEntryPoint(lightClass)) return true
|
is JetClass -> declaration.toLightClass()
|
||||||
return false
|
is JetNamedFunction -> LightClassUtil.getLightClassMethod(declaration)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
return lightElement != null && javaInspection.isEntryPoint(lightElement)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun classHasTextUsages(klass: JetClass): Boolean {
|
private fun classHasTextUsages(klass: JetClass): Boolean {
|
||||||
@@ -88,6 +106,7 @@ public class UnusedSymbolInspection : AbstractKotlinInspection() {
|
|||||||
private fun hasNonTrivialUsages(declaration: JetNamedDeclaration): Boolean {
|
private fun hasNonTrivialUsages(declaration: JetNamedDeclaration): Boolean {
|
||||||
val searchHelper: UsagesSearchHelper<out JetNamedDeclaration> = when (declaration) {
|
val searchHelper: UsagesSearchHelper<out JetNamedDeclaration> = when (declaration) {
|
||||||
is JetClass -> ClassUsagesSearchHelper(constructorUsages = true, nonConstructorUsages = true, skipImports = true)
|
is JetClass -> ClassUsagesSearchHelper(constructorUsages = true, nonConstructorUsages = true, skipImports = true)
|
||||||
|
is JetNamedFunction -> FunctionUsagesSearchHelper(skipImports = true)
|
||||||
else -> return false
|
else -> return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
fun f() {
|
fun main(args: Array<String>) {
|
||||||
class Local {
|
class Local {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
fun f() {
|
fun main(args: Array<String>) {
|
||||||
class Local {
|
class Local {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
class A
|
class A
|
||||||
|
|
||||||
fun f(): A {
|
fun main(args: Array<String>) {
|
||||||
|
val x: A? = null
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
class A {
|
class A {
|
||||||
fun f(other: A) {
|
val x: A? = null
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
open class Klass {
|
||||||
|
fun used() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Subklass: Klass()
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
Subklass().used()
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
open class Klass {
|
||||||
|
open fun used() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Subklass: Klass() {
|
||||||
|
override fun used() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
Subklass().used()
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
class Klass: Iterable<String> {
|
||||||
|
override fun iterator(): Iterator<String> {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
Klass()
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
class Klass {
|
||||||
|
fun unused() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
Klass()
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
class Klass {
|
||||||
|
fun used() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
Klass().used()
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
<problems>
|
||||||
|
<problem>
|
||||||
|
<file>topLevelUnused.kt</file>
|
||||||
|
<line>1</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/topLevelUnused.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Unused Symbol</problem_class>
|
||||||
|
<description>Function 'unused' is never used</description>
|
||||||
|
</problem>
|
||||||
|
|
||||||
|
<problem>
|
||||||
|
<file>topLevelOnlyInImport.kt</file>
|
||||||
|
<line>5</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/topLevelOnlyInImport.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Unused Symbol</problem_class>
|
||||||
|
<description>Function 'onlyInImport' is never used</description>
|
||||||
|
</problem>
|
||||||
|
|
||||||
|
<problem>
|
||||||
|
<file>local.kt</file>
|
||||||
|
<line>2</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/local.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Unused Symbol</problem_class>
|
||||||
|
<description>Function 'local' is never used</description>
|
||||||
|
</problem>
|
||||||
|
<problem>
|
||||||
|
<file>local.kt</file>
|
||||||
|
<line>1</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/local.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Unused Symbol</problem_class>
|
||||||
|
<description>Function 'outer' is never used</description>
|
||||||
|
</problem>
|
||||||
|
|
||||||
|
<problem>
|
||||||
|
<file>usedOnlyRecursively.kt</file>
|
||||||
|
<line>1</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/usedOnlyRecursively.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Unused Symbol</problem_class>
|
||||||
|
<description>Function 'usedOnlyRecursively' is never used</description>
|
||||||
|
</problem>
|
||||||
|
|
||||||
|
<problem>
|
||||||
|
<file>classMemberUnused.kt</file>
|
||||||
|
<line>2</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/classMemberUnused.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Unused Symbol</problem_class>
|
||||||
|
<description>Function 'unused' is never used</description>
|
||||||
|
</problem>
|
||||||
|
</problems>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
// INSPECTION_CLASS: org.jetbrains.kotlin.idea.inspections.UnusedSymbolInspection
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fun outer() {
|
||||||
|
fun local() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun main(args: Array<String>) {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
import foo.onlyInImport
|
||||||
|
|
||||||
|
fun onlyInImport() {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun unused() {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun used() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
used()
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun usedOnlyRecursively() {
|
||||||
|
usedOnlyRecursively()
|
||||||
|
}
|
||||||
@@ -83,5 +83,11 @@ public class JetInspectionTestGenerated extends AbstractJetInspectionTest {
|
|||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/inspections/unusedSymbol/class/inspectionData/inspections.test");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/inspections/unusedSymbol/class/inspectionData/inspections.test");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("unusedSymbol/function/inspectionData/inspections.test")
|
||||||
|
public void testUnusedSymbol_function_inspectionData_Inspections_test() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/inspections/unusedSymbol/function/inspectionData/inspections.test");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user