[groovy] add and use GrSingleResultResolverProcessor

This commit is contained in:
Daniil Ovchinnikov
2018-07-24 19:32:18 +03:00
parent 82367ab25d
commit e7ab0976a7
5 changed files with 30 additions and 24 deletions

View File

@@ -10,7 +10,7 @@ import com.intellij.psi.util.parents
import com.intellij.util.withPrevious import com.intellij.util.withPrevious
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult
import org.jetbrains.plugins.groovy.lang.resolve.ElementResolveResult import org.jetbrains.plugins.groovy.lang.resolve.ElementResolveResult
import org.jetbrains.plugins.groovy.lang.resolve.GrResolverProcessor import org.jetbrains.plugins.groovy.lang.resolve.GrSingleResultResolverProcessor
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil.DECLARATION_SCOPE_PASSED import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil.DECLARATION_SCOPE_PASSED
/** /**
@@ -40,17 +40,13 @@ fun PsiElement.treeWalkUp(processor: PsiScopeProcessor, state: ResolveState = Re
return true return true
} }
fun <T : GroovyResolveResult> PsiElement.treeWalkUpAndGet(processor: GrResolverProcessor<T>): List<T> { fun <T : GroovyResolveResult> PsiElement.treeWalkUpAndGet(processor: GrSingleResultResolverProcessor<T>): T? {
treeWalkUp(processor, ResolveState.initial(), this) treeWalkUp(processor, ResolveState.initial(), this)
return processor.results return processor.result
} }
fun <T : GroovyResolveResult> PsiElement.treeWalkUpAndGetSingleResult(processor: GrResolverProcessor<T>): T? { fun <T : PsiElement> PsiElement.treeWalkUpAndGetElement(processor: GrSingleResultResolverProcessor<ElementResolveResult<T>>): T? {
return treeWalkUpAndGet(processor).singleOrNull() return treeWalkUpAndGet(processor)?.element
}
fun <T : PsiElement> PsiElement.treeWalkUpAndGetSingleElement(processor: GrResolverProcessor<ElementResolveResult<T>>): T? {
return treeWalkUpAndGetSingleResult(processor)?.element
} }
inline fun <reified T : PsiElement> PsiElement.skipParentsOfType(): Pair<PsiElement, PsiElement?>? = skipParentsOfType(true, T::class.java) inline fun <reified T : PsiElement> PsiElement.skipParentsOfType(): Pair<PsiElement, PsiElement?>? = skipParentsOfType(true, T::class.java)

View File

@@ -159,7 +159,7 @@ private fun GrReferenceExpression.doResolveStatic(): GroovyResolveResult? {
val qualifier = qualifier val qualifier = qualifier
if (qualifier == null) { if (qualifier == null) {
val localVariable = resolveToLocalVariable(name).singleOrNull() val localVariable = resolveToLocalVariable(name)
if (localVariable != null) { if (localVariable != null) {
return localVariable return localVariable
} }
@@ -167,7 +167,7 @@ private fun GrReferenceExpression.doResolveStatic(): GroovyResolveResult? {
if (parent !is GrMethodCall) { if (parent !is GrMethodCall) {
if (qualifier == null || qualifier.isThisExpression()) { if (qualifier == null || qualifier.isThisExpression()) {
val field = resolveToField(name).singleOrNull() val field = resolveToField(name)
if (field != null && checkCurrentClass(field.element, this)) { if (field != null && checkCurrentClass(field.element, this)) {
return field return field
} }
@@ -193,7 +193,7 @@ private fun GrReferenceExpression.doResolveStatic(): GroovyResolveResult? {
* @receiver call site * @receiver call site
* @return empty collection or a collection with 1 local variable result * @return empty collection or a collection with 1 local variable result
*/ */
private fun PsiElement.resolveToLocalVariable(name: String): Collection<ElementResolveResult<GrVariable>> { private fun PsiElement.resolveToLocalVariable(name: String): ElementResolveResult<GrVariable>? {
return treeWalkUpAndGet(LocalVariableProcessor(name)) return treeWalkUpAndGet(LocalVariableProcessor(name))
} }
@@ -204,7 +204,7 @@ private fun PsiElement.resolveToLocalVariable(name: String): Collection<ElementR
* @receiver call site * @receiver call site
* @return empty collection or a collection with 1 code field result * @return empty collection or a collection with 1 code field result
*/ */
private fun PsiElement.resolveToField(name: String): Collection<ElementResolveResult<GrField>> { private fun PsiElement.resolveToField(name: String): ElementResolveResult<GrField>? {
return treeWalkUpAndGet(CodeFieldProcessor(name, this)) return treeWalkUpAndGet(CodeFieldProcessor(name, this))
} }

View File

@@ -0,0 +1,11 @@
// Copyright 2000-2018 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.
package org.jetbrains.plugins.groovy.lang.resolve
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult
interface GrSingleResultResolverProcessor<out T : GroovyResolveResult> : GrResolverProcessor<T> {
val result: T?
override val results: List<T> get() = result?.let { listOf(it) } ?: emptyList()
}

View File

@@ -66,7 +66,7 @@ import org.jetbrains.plugins.groovy.lang.resolve.processors.inference.MethodCand
import java.util.*; import java.util.*;
import static org.jetbrains.plugins.groovy.lang.psi.impl.GrAnnotationUtilKt.hasAnnotation; import static org.jetbrains.plugins.groovy.lang.psi.impl.GrAnnotationUtilKt.hasAnnotation;
import static org.jetbrains.plugins.groovy.lang.psi.util.PsiTreeUtilKt.treeWalkUpAndGetSingleElement; import static org.jetbrains.plugins.groovy.lang.psi.util.PsiTreeUtilKt.treeWalkUpAndGetElement;
import static org.jetbrains.plugins.groovy.lang.resolve.ReceiverKt.processReceiverType; import static org.jetbrains.plugins.groovy.lang.resolve.ReceiverKt.processReceiverType;
import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.getDefaultConstructor; import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.getDefaultConstructor;
import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.initialState; import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.initialState;
@@ -874,14 +874,14 @@ public class ResolveUtil {
return duplicates.size() > 0 ? duplicates.get(0) : null; return duplicates.size() > 0 ? duplicates.get(0) : null;
} }
else { else {
PsiNamedElement duplicate = treeWalkUpAndGetSingleElement(variable, new DuplicateVariableProcessor(variable)); PsiNamedElement duplicate = treeWalkUpAndGetElement(variable, new DuplicateVariableProcessor(variable));
final PsiElement context1 = variable.getContext(); final PsiElement context1 = variable.getContext();
if (duplicate == null && variable instanceof GrParameter && context1 != null) { if (duplicate == null && variable instanceof GrParameter && context1 != null) {
final PsiElement context = context1.getContext(); final PsiElement context = context1.getContext();
if (context instanceof GrClosableBlock || if (context instanceof GrClosableBlock ||
context instanceof GrMethod && !(context.getParent() instanceof GroovyFile) || context instanceof GrMethod && !(context.getParent() instanceof GroovyFile) ||
context instanceof GrTryCatchStatement) { context instanceof GrTryCatchStatement) {
duplicate = treeWalkUpAndGetSingleElement(context.getParent(), new DuplicateVariableProcessor(variable)); duplicate = treeWalkUpAndGetElement(context.getParent(), new DuplicateVariableProcessor(variable));
} }
} }
if (duplicate instanceof GrLightParameter && "args".equals(duplicate.getName())) { if (duplicate instanceof GrLightParameter && "args".equals(duplicate.getName())) {

View File

@@ -4,19 +4,18 @@ package org.jetbrains.plugins.groovy.lang.resolve.processors
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.ResolveState import com.intellij.psi.ResolveState
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult
import org.jetbrains.plugins.groovy.lang.resolve.GrResolverProcessor import org.jetbrains.plugins.groovy.lang.resolve.GrSingleResultResolverProcessor
abstract class FindFirstProcessor<T : GroovyResolveResult> : ProcessorWithCommonHints(), GrResolverProcessor<T> { abstract class FindFirstProcessor<out T : GroovyResolveResult> : ProcessorWithCommonHints(), GrSingleResultResolverProcessor<T> {
var result: T? = null private var myResult: T? = null
private set
final override val results: List<T> get() = result?.let { listOf(it) } ?: emptyList() override val result: T? get() = myResult
final override fun execute(element: PsiElement, state: ResolveState): Boolean { final override fun execute(element: PsiElement, state: ResolveState): Boolean {
if (result != null || shouldStop()) return false if (myResult != null || shouldStop()) return false
result = result(element, state) myResult = result(element, state)
return !shouldStop() && result == null return !shouldStop() && myResult == null
} }
protected abstract fun result(element: PsiElement, state: ResolveState): T? protected abstract fun result(element: PsiElement, state: ResolveState): T?