[extract duplicates] clean up: restrict depth by terminal nodes instead of complicated comparator

GitOrigin-RevId: 86e02e7bc54c7f615ab3aeda84143bbd535c5c16
This commit is contained in:
Alexandr Suhinin
2021-08-11 16:54:21 +00:00
committed by intellij-monorepo-bot
parent d854449386
commit 8e9330e280
2 changed files with 16 additions and 12 deletions
@@ -9,7 +9,7 @@ data class ChangedExpression(val pattern: PsiExpression, val candidate: PsiExpre
data class Duplicate(val pattern: List<PsiElement>, val candidate: List<PsiElement>, val changedExpressions: List<ChangedExpression>)
class JavaDuplicatesFinder(pattern: List<PsiElement>) {
class JavaDuplicatesFinder(pattern: List<PsiElement>, private val terminalNodes: Set<PsiElement> = emptySet()) {
companion object {
fun textRangeOf(range: List<PsiElement>) = TextRange(range.first().textRange.startOffset, range.last().textRange.endOffset)
@@ -17,6 +17,10 @@ class JavaDuplicatesFinder(pattern: List<PsiElement>) {
private val pattern: List<PsiElement> = pattern.filterNot(::isNoise)
fun withTerminalNodes(terminalNodes: Set<PsiElement>): JavaDuplicatesFinder {
return JavaDuplicatesFinder(pattern, this.terminalNodes + terminalNodes)
}
fun findDuplicates(scope: PsiElement): List<Duplicate> {
val ignoredElements = pattern.toSet()
val duplicates = mutableListOf<Duplicate>()
@@ -73,11 +77,9 @@ class JavaDuplicatesFinder(pattern: List<PsiElement>) {
?.copy(pattern = listOf(pattern), candidate = listOf(candidate))
}
fun createDuplicate(pattern: List<PsiElement>,
candidate: List<PsiElement>,
equivalenceComparator: (PsiElement, PsiElement) -> Boolean = ::isEquivalent): Duplicate? {
fun createDuplicate(pattern: List<PsiElement>, candidate: List<PsiElement>): Duplicate? {
val changedExpressions = ArrayList<ChangedExpression>()
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<PsiElement>) {
fun traverseAndCollectChanges(pattern: List<PsiElement>,
candidate: List<PsiElement>,
changedExpressions: MutableList<ChangedExpression>,
equivalenceComparator: (PsiElement, PsiElement) -> Boolean): Boolean {
changedExpressions: MutableList<ChangedExpression>): 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) }
@@ -74,10 +74,11 @@ class DuplicatesMethodExtractor: InplaceExtractMethodProvider {
//TODO check same data output
//TODO check same flow output (+ same return values)
val terminalExpressions: Set<PsiExpression> = 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<InputParameter> = findNewParameters(options.inputParameters, duplicates)