[extract duplicates] IDEA-298940: check top level expression nodes to be equal

GitOrigin-RevId: 5f6d408132c2e835434f2b19572e8e1e74fd572d
This commit is contained in:
Alexandr Suhinin
2022-11-23 12:39:14 +00:00
committed by intellij-monorepo-bot
parent 8d505bd015
commit 214599080e
4 changed files with 43 additions and 9 deletions
@@ -46,9 +46,13 @@ class JavaDuplicatesFinder(pattern: List<PsiElement>, private val predefinedChan
object : JavaRecursiveElementWalkingVisitor(){
override fun visitExpression(expression: PsiExpression) {
if (expression in ignoredElements) return
val duplicate = createDuplicate(childrenOf(patternExpression), childrenOf(expression))
val duplicate = if (areNodesEquivalent(patternExpression, expression)) {
createDuplicate(listOf(patternExpression), listOf(expression))
} else {
null
}
if (duplicate != null) {
duplicates += duplicate.copy(pattern = listOf(patternExpression), candidate = listOf(expression))
duplicates += duplicate
} else {
super.visitExpression(expression)
}
@@ -88,11 +92,6 @@ class JavaDuplicatesFinder(pattern: List<PsiElement>, private val predefinedChan
return siblingsOf(element?.firstChild).toList()
}
fun createExpressionDuplicate(pattern: PsiExpression, candidate: PsiExpression): Duplicate? {
return createDuplicate(childrenOf(pattern), childrenOf(candidate))
?.copy(pattern = listOf(pattern), candidate = listOf(candidate))
}
fun createDuplicate(pattern: List<PsiElement>, candidate: List<PsiElement>): Duplicate? {
val changedExpressions = ArrayList<ChangedExpression>()
if (!traverseAndCollectChanges(pattern, candidate, changedExpressions)) return null
@@ -120,13 +119,18 @@ class JavaDuplicatesFinder(pattern: List<PsiElement>, private val predefinedChan
return duplicate.copy(changedExpressions = changedExpressions)
}
/**
* Does recursive equivalence check for [pattern] and [candidate] nodes.
* Puts parametrized expressions into [changedExpressions] list.
* @return false if are [pattern] and [candidate] are not parametrized duplicates.
*/
private fun traverseAndCollectChanges(pattern: List<PsiElement>,
candidate: List<PsiElement>,
changedExpressions: MutableList<ChangedExpression>): Boolean {
if (candidate.size != pattern.size) return false
val notEqualElements = pattern.zip(candidate).filterNot { (pattern, candidate) ->
pattern !in predefinedChanges &&
areEquivalent(pattern, candidate) &&
areNodesEquivalent(pattern, candidate) &&
traverseAndCollectChanges(childrenOf(pattern), childrenOf(candidate), changedExpressions)
}
if (notEqualElements.any { (pattern, candidate) -> ! canBeReplaced(pattern, candidate) }) return false
@@ -134,7 +138,10 @@ class JavaDuplicatesFinder(pattern: List<PsiElement>, private val predefinedChan
return true
}
private fun areEquivalent(pattern: PsiElement, candidate: PsiElement): Boolean {
/**
* Non-recursive equivalence check for [pattern] and [candidate] elements.
*/
private fun areNodesEquivalent(pattern: PsiElement, candidate: PsiElement): Boolean {
return when {
pattern is PsiTypeElement && candidate is PsiTypeElement -> canBeReplaced(pattern.type, candidate.type)
pattern is PsiJavaCodeReferenceElement && candidate is PsiJavaCodeReferenceElement ->
@@ -0,0 +1,8 @@
public class Test {
void test() {
String first = <selection>"First"</selection>;
String second = "First";
String third = "Third";
}
}
@@ -0,0 +1,15 @@
import org.jetbrains.annotations.NotNull;
public class Test {
void test() {
String first = getFirst();
String second = getFirst();
String third = "Third";
}
@NotNull
private static String getFirst() {
return "First";
}
}
@@ -238,6 +238,10 @@ class ExtractMethodAndDuplicatesInplaceTest: LightJavaCodeInsightTestCase() {
doTest()
}
fun testLiteralDuplicates(){
doTest()
}
fun testFoldedParametersInExactDuplicates(){
val default = DuplicatesMethodExtractor.changeSignatureDefault
try {