Simplify for intention refactoring: focus on the loop parameter, not on the loop itself

This commit is contained in:
Mikhail Glukhikh
2016-10-03 11:30:14 +03:00
parent 0a8006a395
commit 42aea59253
12 changed files with 83 additions and 87 deletions
@@ -0,0 +1,5 @@
<html>
<body>
This inspection reports any declarations that can be destructured
</body>
</html>
@@ -1,5 +0,0 @@
<html>
<body>
This inspection reports any for expressions that can be simplified
</body>
</html>
@@ -0,0 +1,5 @@
<html>
<body>
This intention destructures declaration (of parameter or variable of data class / map entry type)
</body>
</html>
@@ -1,5 +0,0 @@
<html>
<body>
This intention simplifies for expression by replacing iteration over map entries and collections of data classes with destructing declaration
</body>
</html>
+3 -3
View File
@@ -1251,7 +1251,7 @@
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.SimplifyForIntention</className>
<className>org.jetbrains.kotlin.idea.intentions.DestructureIntention</className>
<category>Kotlin</category>
</intentionAction>
@@ -1638,8 +1638,8 @@
language="kotlin"
/>
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.SimplifyForInspection"
displayName="'for' that can be simplified using destructing declaration"
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.DestructureInspection"
displayName="Can be simplified using destructing declaration"
groupName="Kotlin"
enabledByDefault="true"
cleanupTool="false"
@@ -38,18 +38,17 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import java.util.*
class SimplifyForInspection : IntentionBasedInspection<KtForExpression>(SimplifyForIntention::class)
class DestructureInspection : IntentionBasedInspection<KtParameter>(DestructureIntention::class)
class SimplifyForIntention : SelfTargetingRangeIntention<KtForExpression>(
KtForExpression::class.java,
"Simplify 'for' using destructuring declaration",
"Simplify 'for'"
class DestructureIntention : SelfTargetingRangeIntention<KtParameter>(
KtParameter::class.java,
"Simplify using destructuring declaration"
) {
override fun applyTo(element: KtForExpression, editor: Editor?) {
val (usagesToRemove, removeSelectorInLoopRange) = collectUsagesToRemove(element) ?: return
override fun applyTo(element: KtParameter, editor: Editor?) {
val forLoop = element.parent as? KtForExpression
val (usagesToRemove, removeSelectorInLoopRange) = collectUsagesToRemove(element, forLoop) ?: return
val loopRange = element.loopRange ?: return
val loopParameter = element.loopParameter ?: return
val loopRange = forLoop?.loopRange
val factory = KtPsiFactory(element)
val validator = NewDeclarationNameValidator(element.parent, element, NewDeclarationNameValidator.Target.VARIABLES,
@@ -63,41 +62,38 @@ class SimplifyForIntention : SelfTargetingRangeIntention<KtForExpression>(
}
names.add(name)
}
loopParameter.replace(factory.createDestructuringDeclarationInFor("(${names.joinToString()})"))
element.replace(factory.createDestructuringDeclarationInFor("(${names.joinToString()})"))
if (removeSelectorInLoopRange && loopRange is KtDotQualifiedExpression) {
loopRange.replace(loopRange.receiverExpression)
}
}
override fun applicabilityRange(element: KtForExpression): TextRange? {
if (element.destructuringParameter != null) return null
val usagesToRemove = collectUsagesToRemove(element)
override fun applicabilityRange(element: KtParameter): TextRange? {
val forLoop = element.parent as? KtForExpression ?: return null
val usagesToRemove = collectUsagesToRemove(element, forLoop)
if (usagesToRemove != null && usagesToRemove.first.isNotEmpty()) {
return element.loopParameter!!.textRange
return element.textRange
}
return null
}
// Note: list should contains properties in order to create destructuring declaration
private fun collectUsagesToRemove(element: KtForExpression): Pair<List<UsageData>, Boolean>? {
val loopParameter = element.loopParameter ?: return null
private fun collectUsagesToRemove(parameter: KtParameter, forLoop: KtForExpression?): Pair<List<UsageData>, Boolean>? {
val context = parameter.analyzeFullyAndGetResult().bindingContext
val context = element.analyzeFullyAndGetResult().bindingContext
val loopParameterDescriptor = context.get(BindingContext.VALUE_PARAMETER, loopParameter) ?: return null
val loopParameterType = loopParameterDescriptor.type
if (loopParameterType.isMarkedNullable) return null
val classDescriptor = loopParameterType.constructor.declarationDescriptor as? ClassDescriptor ?: return null
val parameterDescriptor = context.get(BindingContext.VALUE_PARAMETER, parameter) ?: return null
val parameterType = parameterDescriptor.type
if (parameterType.isMarkedNullable) return null
val classDescriptor = parameterType.constructor.declarationDescriptor as? ClassDescriptor ?: return null
var otherUsages = false
val usagesToRemove : Array<UsageData>
val mapEntry = classDescriptor.builtIns.mapEntry
val removeSelectorInLoopRange: Boolean
if (DescriptorUtils.isSubclass(classDescriptor, mapEntry)) {
val loopRangeDescriptorName = element.loopRange.getResolvedCall(context)?.resultingDescriptor?.name
if (forLoop != null && DescriptorUtils.isSubclass(classDescriptor, mapEntry)) {
val loopRangeDescriptorName = forLoop.loopRange.getResolvedCall(context)?.resultingDescriptor?.name
removeSelectorInLoopRange = loopRangeDescriptorName?.asString().let { it == "entries" || it == "entrySet" }
usagesToRemove = Array(2, {
@@ -105,7 +101,7 @@ class SimplifyForIntention : SelfTargetingRangeIntention<KtForExpression>(
NoLookupLocation.FROM_BUILTINS).first())
})
ReferencesSearch.search(loopParameter).iterateOverMapEntryPropertiesUsages(
ReferencesSearch.search(parameter).iterateOverMapEntryPropertiesUsages(
context,
{ index, usageData -> usagesToRemove[index] += usageData },
{ otherUsages = true }
@@ -117,7 +113,7 @@ class SimplifyForIntention : SelfTargetingRangeIntention<KtForExpression>(
val valueParameters = classDescriptor.unsubstitutedPrimaryConstructor?.valueParameters ?: return null
usagesToRemove = Array(valueParameters.size, { UsageData(valueParameters[it] )})
ReferencesSearch.search(loopParameter).iterateOverDataClassPropertiesUsagesWithIndex(
ReferencesSearch.search(parameter).iterateOverDataClassPropertiesUsagesWithIndex(
context,
classDescriptor,
{ index, usageData -> usagesToRemove[index] += usageData },
@@ -68,7 +68,7 @@ object J2KPostProcessingRegistrar {
registerIntentionBasedProcessing(ObjectLiteralToLambdaIntention())
registerIntentionBasedProcessing(AnonymousFunctionToLambdaIntention())
registerIntentionBasedProcessing(RemoveUnnecessaryParenthesesIntention())
registerIntentionBasedProcessing(SimplifyForIntention())
registerIntentionBasedProcessing(DestructureIntention())
registerIntentionBasedProcessing(SimplifyAssertNotNullIntention())
registerDiagnosticBasedProcessing<KtBinaryExpressionWithTypeRHS>(Errors.USELESS_CAST) { element, diagnostic ->
+1 -1
View File
@@ -1 +1 @@
org.jetbrains.kotlin.idea.intentions.SimplifyForIntention
org.jetbrains.kotlin.idea.intentions.DestructureIntention
@@ -4,175 +4,175 @@
<line>4</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="SomeQualifiedExpressionInRange.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Simplify 'for' using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>Simple.kt</file>
<line>5</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="Simple.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Simplify 'for' using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>PropertiesNames.kt</file>
<line>5</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="PropertiesNames.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Simplify 'for' using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>Getters.kt</file>
<line>5</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="Getters.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Simplify 'for' using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>DataClassParametersOrder.kt</file>
<line>5</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="DataClassParametersOrder.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Simplify 'for' using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>DataClass.kt</file>
<line>5</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="DataClass.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Simplify 'for' using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>EntriesCallIsMissing.kt</file>
<line>6</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="EntriesCallIsMissing.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Simplify 'for' using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>DataClassFirstNPropertiesUsed.kt</file>
<line>5</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="DataClassFirstNPropertiesUsed.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Simplify 'for' using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>CaretOffset.kt</file>
<line>6</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="CaretOffset.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Simplify 'for' using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>DataClassNoVariablesInside.kt</file>
<line>5</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/DataClassNoVariablesInside.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'for' that can be simplified using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>DataClassNoVariablesMultiUsages.kt</file>
<line>5</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/DataClassNoVariablesMultiUsages.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'for' that can be simplified using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>DataClassPropertyBetweenUsages.kt</file>
<line>5</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/DataClassPropertyBetweenUsages.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'for' that can be simplified using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>DataClassSecondVariable.kt</file>
<line>5</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/DataClassSecondVariable.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'for' that can be simplified using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>DataClassWithExternalUsage.kt</file>
<line>5</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/DataClassWithExternalUsage.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'for' that can be simplified using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>DataClassDependentLocal.kt</file>
<line>6</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/DataClassDependentLocal.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'for' that can be simplified using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>DataClassFirstVariable.kt</file>
<line>5</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/DataClassFirstVariable.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'for' that can be simplified using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>MapNoProperties.kt</file>
<line>4</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/MapNoProperties.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'for' that can be simplified using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>ValueOnly.kt</file>
<line>5</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/ValueOnly.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'for' that can be simplified using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>KeyOnly.kt</file>
<line>5</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/KeyOnly.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'for' that can be simplified using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>DataClassNotAllPropertiesUsed.kt</file>
<line>5</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/DataClassNotAllPropertiesUsed.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'for' that can be simplified using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>DataClassLast.kt</file>
<line>6</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/DataClassLast.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'for' that can be simplified using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
<problem>
<file>DataClassNameConflict.kt</file>
<line>7</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/DataClassNameConflict.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'for' that can be simplified using destructuring declaration</problem_class>
<description>Simplify 'for' using destructuring declaration</description>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can be simplified using destructuring declaration</problem_class>
<description>Simplify using destructuring declaration</description>
</problem>
</problems>
@@ -1 +1 @@
// INSPECTION_CLASS: org.jetbrains.kotlin.idea.intentions.SimplifyForInspection
// INSPECTION_CLASS: org.jetbrains.kotlin.idea.intentions.DestructureInspection