KT-9839 related, secondary constructor to primary: inspection for the single constructor

This commit is contained in:
Mikhail Glukhikh
2016-09-30 14:03:56 +03:00
parent 48a1853d6d
commit aec0090ae2
7 changed files with 69 additions and 11 deletions

View File

@@ -0,0 +1,5 @@
<html>
<body>
This inspection reports secondary constructor that can be replaced with more concise primary constructor
</body>
</html>

View File

@@ -1771,6 +1771,14 @@
language="kotlin"
/>
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ConvertSecondaryConstructorToPrimaryInspection"
displayName="Convert to primary constructor"
groupName="Kotlin"
enabledByDefault="true"
level="WARNING"
language="kotlin"
/>
<referenceImporter implementation="org.jetbrains.kotlin.idea.quickfix.KotlinReferenceImporter"/>
<fileType.fileViewProviderFactory filetype="KJSM" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/>

View File

@@ -17,17 +17,26 @@
package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
import org.jetbrains.kotlin.idea.util.CommentSaver
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClass
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
class ConvertSecondaryConstructorToPrimaryIntention : SelfTargetingIntention<KtSecondaryConstructor>(
class ConvertSecondaryConstructorToPrimaryInspection : IntentionBasedInspection<KtSecondaryConstructor>(
ConvertSecondaryConstructorToPrimaryIntention::class,
{ constructor -> constructor.containingClass()?.getSecondaryConstructors()?.size == 1 }
) {
override fun inspectionTarget(element: KtSecondaryConstructor) = element.getConstructorKeyword()
}
class ConvertSecondaryConstructorToPrimaryIntention : SelfTargetingRangeIntention<KtSecondaryConstructor>(
KtSecondaryConstructor::class.java,
"Convert to primary constructor"
) {
@@ -41,22 +50,22 @@ class ConvertSecondaryConstructorToPrimaryIntention : SelfTargetingIntention<KtS
return isReachableByDelegationFrom(delegationDescriptor, context, visited + constructor)
}
override fun isApplicableTo(element: KtSecondaryConstructor, caretOffset: Int): Boolean {
override fun applicabilityRange(element: KtSecondaryConstructor): TextRange? {
val delegationCall = element.getDelegationCall()
if (delegationCall.isCallToThis) return false
val klass = element.containingClassOrObject ?: return false
if (klass.hasPrimaryConstructor()) return false
if (delegationCall.isCallToThis) return null
val klass = element.containingClassOrObject ?: return null
if (klass.hasPrimaryConstructor()) return null
val context = klass.analyze()
val classDescriptor = context[BindingContext.CLASS, klass] ?: return false
val elementDescriptor = context[BindingContext.CONSTRUCTOR, element] ?: return false
val context = klass.analyzeFully()
val classDescriptor = context[BindingContext.CLASS, klass] ?: return null
val elementDescriptor = context[BindingContext.CONSTRUCTOR, element] ?: return null
for (constructorDescriptor in classDescriptor.constructors) {
if (constructorDescriptor == elementDescriptor) continue
if (!elementDescriptor.isReachableByDelegationFrom(constructorDescriptor, context)) return false
if (!elementDescriptor.isReachableByDelegationFrom(constructorDescriptor, context)) return null
}
return true
return element.textRange
}
private fun KtExpression.tryConvertToPropertyByParameterInitialization(

View File

@@ -0,0 +1,10 @@
<problems>
<problem>
<file>test.kt</file>
<line>5</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert to primary constructor</problem_class>
<description>Convert to primary constructor</description>
</problem>
</problems>

View File

@@ -0,0 +1 @@
// INSPECTION_CLASS: org.jetbrains.kotlin.idea.intentions.ConvertSecondaryConstructorToPrimaryInspection

View File

@@ -0,0 +1,19 @@
class Single {
val x: Int
constructor(x: Int) {
this.x = x
}
}
class NotSingle {
val x: Int
constructor(): this(42)
constructor(x: Int) {
this.x = x
}
}

View File

@@ -154,6 +154,12 @@ public class InspectionTestGenerated extends AbstractInspectionTest {
doTest(fileName);
}
@TestMetadata("convertSecondaryToPrimary/inspectionData/inspections.test")
public void testConvertSecondaryToPrimary_inspectionData_Inspections_test() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspections/convertSecondaryToPrimary/inspectionData/inspections.test");
doTest(fileName);
}
@TestMetadata("equalsAndHashCode/inspectionData/inspections.test")
public void testEqualsAndHashCode_inspectionData_Inspections_test() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspections/equalsAndHashCode/inspectionData/inspections.test");