mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-228815: Do not use references with recursive calls
GitOrigin-RevId: e4f13ec8bc709f2b543db8122455b3abf9ecb977
This commit is contained in:
committed by
intellij-monorepo-bot
parent
b64d3b665a
commit
54e5e4d2ea
+51
-12
@@ -1,4 +1,6 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
@file:Suppress("RemoveExplicitTypeArguments")
|
||||
|
||||
package org.jetbrains.plugins.groovy.intentions.style.inference.search
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
@@ -7,11 +9,16 @@ import com.intellij.psi.search.*
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import com.intellij.psi.util.parentOfType
|
||||
import com.intellij.util.Processor
|
||||
import com.intellij.util.containers.map2Array
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GrFunctionalExpression
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod
|
||||
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
|
||||
internal fun searchWithClosureAvoidance(element: GrMethod, scope: SearchScope): List<PsiReference> {
|
||||
val requestsCollector = SearchRequestCollector(SearchSession())
|
||||
val collector: MutableList<PsiReference> = mutableListOf<PsiReference>()
|
||||
@@ -21,28 +28,60 @@ internal fun searchWithClosureAvoidance(element: GrMethod, scope: SearchScope):
|
||||
val query: QuerySearchRequest = queries.removeAt(queries.lastIndex)
|
||||
if (!query.runQuery()) break
|
||||
query.collector.takeQueryRequests().forEach { queries.add(it) }
|
||||
query.collector.takeSearchRequests().forEach { dumpSearchRequest(requestsCollector, it, element) }
|
||||
query.collector.takeSearchRequests().forEach { requestsCollector.adoptSearchRequest(it, element) }
|
||||
}
|
||||
PsiSearchHelper.getInstance(element.project).processRequests(requestsCollector) { ref -> collector.add(ref); true }
|
||||
return collector
|
||||
}
|
||||
|
||||
private fun dumpSearchRequest(requestsCollector: SearchRequestCollector, request: PsiSearchRequest, target: GrMethod) = with(request) {
|
||||
requestsCollector.searchWord(word, searchScope, searchContext, caseSensitive, target, ScopeFilteringRequestProcessor(target, processor))
|
||||
private fun SearchRequestCollector.adoptSearchRequest(request: PsiSearchRequest, target: GrMethod) = with(request) {
|
||||
searchWord(word, searchScope, searchContext, caseSensitive, target, ScopeFilteringRequestProcessor(target, processor))
|
||||
}
|
||||
|
||||
private class ScopeFilteringRequestProcessor(private val anchorElement: GrMethod,
|
||||
private val delegateProcessor: RequestResultProcessor) : RequestResultProcessor() {
|
||||
override fun processTextOccurrence(element: PsiElement, offsetInElement: Int, consumer: Processor<in PsiReference>): Boolean {
|
||||
val enclosingClosure = element.parentOfType<GrFunctionalExpression>()
|
||||
val call = enclosingClosure?.parentOfType<GrMethodCall>()
|
||||
val arguments = call?.closureArguments?.asList()?.plus(call.expressionArguments.asList())
|
||||
if (arguments?.contains(enclosingClosure) == true && call.callReference?.methodName == anchorElement.name) {
|
||||
return true
|
||||
|
||||
private class CollisionFinder(vararg val bannedIdentifiers: String) : GroovyRecursiveElementVisitor() {
|
||||
var foundCollision = false
|
||||
|
||||
override fun visitElement(element: GroovyPsiElement) {
|
||||
if (!foundCollision) super.visitElement(element)
|
||||
}
|
||||
else {
|
||||
return delegateProcessor.processTextOccurrence(element, offsetInElement, consumer)
|
||||
|
||||
override fun visitReferenceExpression(referenceExpression: GrReferenceExpression) {
|
||||
if (referenceExpression.referenceName in bannedIdentifiers) {
|
||||
foundCollision = true
|
||||
}
|
||||
else {
|
||||
super.visitReferenceExpression(referenceExpression)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFunctionalExpression(expression: GrFunctionalExpression) {
|
||||
// it is sufficient for references searcher to know that argument has closure type, no need to go deeper
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun processTextOccurrence(element: PsiElement, offsetInElement: Int, consumer: Processor<in PsiReference>): Boolean {
|
||||
val enclosingClosure: GrFunctionalExpression? = element.parentOfType<GrFunctionalExpression>()
|
||||
val call: GrMethodCall? = enclosingClosure?.parentOfType<GrMethodCall>()
|
||||
val arguments: List<GrExpression>? = call?.closureArguments?.asList()?.plus(call.expressionArguments.asList())
|
||||
if (arguments?.contains(enclosingClosure) == true && call.callReference?.methodName == anchorElement.name) {
|
||||
return true
|
||||
}
|
||||
val enclosingCall: GrMethodCall? = element.parentOfType<GrMethodCall>()?.takeIf { it.invokedExpression === element }
|
||||
if (enclosingCall is GrMethodCall) {
|
||||
val enclosingMethod: GrMethod? = enclosingCall.parentOfType<GrMethod>()?.takeIf { it === anchorElement }
|
||||
val bannedIdentifiers: Array<String> = enclosingMethod?.parameters?.map2Array { it.name } ?: emptyArray()
|
||||
val collisionFinder = CollisionFinder(anchorElement.name, *bannedIdentifiers)
|
||||
if (enclosingCall.expressionArguments.any { argument -> collisionFinder.apply { argument.accept(this) }.foundCollision }) {
|
||||
// there should be provided some connection between method return type and its argument,
|
||||
// but currently this option is absent
|
||||
return true
|
||||
}
|
||||
}
|
||||
return delegateProcessor.processTextOccurrence(element, offsetInElement, consumer)
|
||||
}
|
||||
|
||||
}
|
||||
+4
@@ -560,4 +560,8 @@ class AA { static void fo<caret>o(Integer a) {} }
|
||||
void testForInLoopWithMap() {
|
||||
doTest(true)
|
||||
}
|
||||
|
||||
void testRecursiveCalls() {
|
||||
doTest(true)
|
||||
}
|
||||
}
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
def foo(x) {
|
||||
x
|
||||
}
|
||||
|
||||
def bar() {
|
||||
foo(foo(1))
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
Integer foo(Integer x) {
|
||||
x
|
||||
}
|
||||
|
||||
def bar() {
|
||||
foo(foo(1))
|
||||
}
|
||||
Reference in New Issue
Block a user