diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/ProtectedInFinalInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/ProtectedInFinalInspection.kt index 4962e5b8182..97eac9a4538 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/ProtectedInFinalInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/ProtectedInFinalInspection.kt @@ -9,16 +9,16 @@ import com.intellij.codeInsight.FileModificationService import com.intellij.codeInspection.* import com.intellij.openapi.project.Project import com.intellij.psi.PsiElementVisitor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.idea.core.implicitVisibility import org.jetbrains.kotlin.idea.core.isInheritable -import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor +import org.jetbrains.kotlin.idea.intentions.isFinalizeMethod import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.KtClass +import org.jetbrains.kotlin.psi.KtModifierListOwner import org.jetbrains.kotlin.psi.addRemoveModifier.addModifier +import org.jetbrains.kotlin.psi.declarationVisitor import org.jetbrains.kotlin.psi.psiUtil.getParentOfType import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier -import org.jetbrains.kotlin.types.typeUtil.isUnit class ProtectedInFinalInspection : AbstractKotlinInspection() { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { @@ -43,13 +43,6 @@ class ProtectedInFinalInspection : AbstractKotlinInspection() { }) } - private fun KtDeclaration.isFinalizeMethod(): Boolean { - val function = this as? KtNamedFunction ?: return false - return function.name == "finalize" - && function.valueParameters.isEmpty() - && (function.descriptor as? FunctionDescriptor)?.returnType?.isUnit() == true - } - class MakePrivateFix : LocalQuickFix { override fun getName(): String = "Make private" diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt index c85fe29ff7c..7d6221fe385 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt @@ -46,6 +46,7 @@ import org.jetbrains.kotlin.idea.core.toDescriptor import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesHandlerFactory import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindClassUsagesHandler import org.jetbrains.kotlin.idea.imports.importableFqName +import org.jetbrains.kotlin.idea.intentions.isFinalizeMethod import org.jetbrains.kotlin.idea.isMainFunction import org.jetbrains.kotlin.idea.project.languageVersionSettings import org.jetbrains.kotlin.idea.quickfix.RemoveUnusedFunctionParameterFix @@ -168,6 +169,7 @@ class UnusedSymbolInspection : AbstractKotlinInspection() { val descriptor = declaration.resolveToDescriptorIfAny() ?: return if (descriptor is FunctionDescriptor && descriptor.isOperator) return if (isEntryPoint(declaration)) return + if (declaration.isFinalizeMethod(descriptor)) return if (declaration is KtProperty && declaration.isSerializationImplicitlyUsedField()) return if (declaration is KtNamedFunction && declaration.isSerializationImplicitlyUsedMethod()) return // properties can be referred by component1/component2, which is too expensive to search, don't mark them as unused @@ -283,7 +285,7 @@ class UnusedSymbolInspection : AbstractKotlinInspection() { if (import.importedFqName != declaration.fqName) { val importedDeclaration = import.importedReference?.getQualifiedElementSelector()?.mainReference?.resolve() as? KtNamedDeclaration - ?: return true + ?: return true if (declaration is KtObjectDeclaration || (declaration is KtClass && declaration.isEnum()) || importedDeclaration.containingClassOrObject is KtObjectDeclaration diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt index 71a94de671a..6cbdd770205 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt @@ -19,17 +19,17 @@ package org.jetbrains.kotlin.idea.intentions import com.intellij.psi.tree.IElementType import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall import org.jetbrains.kotlin.idea.core.replaced import org.jetbrains.kotlin.idea.core.setType import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.containingClass import org.jetbrains.kotlin.psi.psiUtil.getCallNameExpression import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.resolve.BindingContext @@ -40,6 +40,7 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.isFlexible +import org.jetbrains.kotlin.types.typeUtil.isUnit import java.lang.IllegalArgumentException fun KtContainerNode.description(): String? { @@ -311,4 +312,12 @@ fun KtBlockExpression.getParentLambdaLabelName(): String? { return lambdaLabelName ?: callExpression.getCallNameExpression()?.text } -internal fun KtExpression.getCallableDescriptor() = resolveToCall()?.resultingDescriptor \ No newline at end of file +internal fun KtExpression.getCallableDescriptor() = resolveToCall()?.resultingDescriptor + +fun KtDeclaration.isFinalizeMethod(descriptor: DeclarationDescriptor? = null): Boolean { + if (containingClass() == null) return false + val function = this as? KtNamedFunction ?: return false + return function.name == "finalize" + && function.valueParameters.isEmpty() + && ((descriptor ?: function.descriptor) as? FunctionDescriptor)?.returnType?.isUnit() == true +} \ No newline at end of file diff --git a/idea/testData/inspections/unusedSymbol/function/finalize.kt b/idea/testData/inspections/unusedSymbol/function/finalize.kt new file mode 100644 index 00000000000..005fa6beb27 --- /dev/null +++ b/idea/testData/inspections/unusedSymbol/function/finalize.kt @@ -0,0 +1,4 @@ +class C { + protected fun finalize() { + } +} \ No newline at end of file diff --git a/idea/testData/inspections/unusedSymbol/function/inspectionData/expected.xml b/idea/testData/inspections/unusedSymbol/function/inspectionData/expected.xml index c8de5ceba0b..81cbcf2e8cc 100644 --- a/idea/testData/inspections/unusedSymbol/function/inspectionData/expected.xml +++ b/idea/testData/inspections/unusedSymbol/function/inspectionData/expected.xml @@ -87,4 +87,13 @@ Unused symbol Function "foo" is never used + + + finalize.kt + 1 + light_idea_test_case + + Unused symbol + Class "C" is never used +