From 8e9330e280f9477b4e3e96ff0bca55166d6e46ef Mon Sep 17 00:00:00 2001 From: Alexandr Suhinin Date: Wed, 11 Aug 2021 15:23:03 +0300 Subject: [PATCH] [extract duplicates] clean up: restrict depth by terminal nodes instead of complicated comparator GitOrigin-RevId: 86e02e7bc54c7f615ab3aeda84143bbd535c5c16 --- .../newImpl/JavaDuplicatesFinder.kt | 19 +++++++++++-------- .../inplace/DuplicatesMethodExtractor.kt | 9 +++++---- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/newImpl/JavaDuplicatesFinder.kt b/java/java-impl/src/com/intellij/refactoring/extractMethod/newImpl/JavaDuplicatesFinder.kt index d3b958fca28c..6f259239fdfd 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/newImpl/JavaDuplicatesFinder.kt +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/newImpl/JavaDuplicatesFinder.kt @@ -9,7 +9,7 @@ data class ChangedExpression(val pattern: PsiExpression, val candidate: PsiExpre data class Duplicate(val pattern: List, val candidate: List, val changedExpressions: List) -class JavaDuplicatesFinder(pattern: List) { +class JavaDuplicatesFinder(pattern: List, private val terminalNodes: Set = emptySet()) { companion object { fun textRangeOf(range: List) = TextRange(range.first().textRange.startOffset, range.last().textRange.endOffset) @@ -17,6 +17,10 @@ class JavaDuplicatesFinder(pattern: List) { private val pattern: List = pattern.filterNot(::isNoise) + fun withTerminalNodes(terminalNodes: Set): JavaDuplicatesFinder { + return JavaDuplicatesFinder(pattern, this.terminalNodes + terminalNodes) + } + fun findDuplicates(scope: PsiElement): List { val ignoredElements = pattern.toSet() val duplicates = mutableListOf() @@ -73,11 +77,9 @@ class JavaDuplicatesFinder(pattern: List) { ?.copy(pattern = listOf(pattern), candidate = listOf(candidate)) } - fun createDuplicate(pattern: List, - candidate: List, - equivalenceComparator: (PsiElement, PsiElement) -> Boolean = ::isEquivalent): Duplicate? { + fun createDuplicate(pattern: List, candidate: List): Duplicate? { val changedExpressions = ArrayList() - if (!traverseAndCollectChanges(pattern, candidate, changedExpressions, equivalenceComparator)) return null + if (!traverseAndCollectChanges(pattern, candidate, changedExpressions)) return null return removeInternalReferences(Duplicate(pattern, candidate, changedExpressions)) } @@ -99,11 +101,12 @@ class JavaDuplicatesFinder(pattern: List) { fun traverseAndCollectChanges(pattern: List, candidate: List, - changedExpressions: MutableList, - equivalenceComparator: (PsiElement, PsiElement) -> Boolean): Boolean { + changedExpressions: MutableList): Boolean { if (candidate.size != pattern.size) return false val notEqualElements = pattern.zip(candidate).filterNot { (pattern, candidate) -> - equivalenceComparator(pattern, candidate) && traverseAndCollectChanges(childrenOf(pattern), childrenOf(candidate), changedExpressions, equivalenceComparator) + pattern !in terminalNodes && + isEquivalent(pattern, candidate) && + traverseAndCollectChanges(childrenOf(pattern), childrenOf(candidate), changedExpressions) } if (notEqualElements.any { (pattern, candidate) -> ! canBeReplaced(pattern, candidate) }) return false changedExpressions += notEqualElements.map { (pattern, candidate) -> ChangedExpression(pattern as PsiExpression, candidate as PsiExpression) } diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/newImpl/inplace/DuplicatesMethodExtractor.kt b/java/java-impl/src/com/intellij/refactoring/extractMethod/newImpl/inplace/DuplicatesMethodExtractor.kt index 52e196c931ce..9ccd059d1750 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/newImpl/inplace/DuplicatesMethodExtractor.kt +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/newImpl/inplace/DuplicatesMethodExtractor.kt @@ -74,10 +74,11 @@ class DuplicatesMethodExtractor: InplaceExtractMethodProvider { //TODO check same data output //TODO check same flow output (+ same return values) - val terminalExpressions: Set = options.inputParameters.flatMap { parameter -> parameter.references }.toSet() - val changes = duplicates.flatMap { it.changedExpressions.map(ChangedExpression::pattern) }.toSet() + terminalExpressions - fun isEquivalent(pattern: PsiElement, candidate: PsiElement) = pattern !in changes && finder.isEquivalent(pattern, candidate) - duplicates = duplicates.mapNotNull { finder.createDuplicate(it.pattern, it.candidate, ::isEquivalent) } + val parameterExpressions = options.inputParameters.flatMap { parameter -> parameter.references } + val changedExpressions = duplicates.flatMap { it.changedExpressions.map(ChangedExpression::pattern) } + val duplicatesFinder = finder.withTerminalNodes((parameterExpressions + changedExpressions).toSet()) + + duplicates = duplicates.mapNotNull { duplicatesFinder.createDuplicate(it.pattern, it.candidate) } val updatedParameters: List = findNewParameters(options.inputParameters, duplicates)