mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-05 01:50:56 +07:00
[junit 5] use multiResolve instead of fastResolveFor for @MethodSource
GitOrigin-RevId: 5f36021929cf0b2017cd09aad869c88998eeed27
This commit is contained in:
committed by
intellij-monorepo-bot
parent
4542127eeb
commit
913adcc0c5
@@ -16,6 +16,7 @@ import com.intellij.codeInspection.util.InspectionMessage
|
|||||||
import com.intellij.execution.JUnitBundle
|
import com.intellij.execution.JUnitBundle
|
||||||
import com.intellij.execution.junit.*
|
import com.intellij.execution.junit.*
|
||||||
import com.intellij.execution.junit.references.MethodSourceReference
|
import com.intellij.execution.junit.references.MethodSourceReference
|
||||||
|
import com.intellij.execution.junit.references.PsiMethodSourceResolveResult
|
||||||
import com.intellij.jvm.analysis.quickFix.CompositeModCommandQuickFix
|
import com.intellij.jvm.analysis.quickFix.CompositeModCommandQuickFix
|
||||||
import com.intellij.jvm.analysis.quickFix.createModifierQuickfixes
|
import com.intellij.jvm.analysis.quickFix.createModifierQuickfixes
|
||||||
import com.intellij.lang.Language
|
import com.intellij.lang.Language
|
||||||
@@ -562,12 +563,15 @@ private class JUnitMalformedSignatureVisitor(
|
|||||||
annotationMemberValue.forEach { attributeValue ->
|
annotationMemberValue.forEach { attributeValue ->
|
||||||
for (reference in attributeValue.references) {
|
for (reference in attributeValue.references) {
|
||||||
if (reference is MethodSourceReference) {
|
if (reference is MethodSourceReference) {
|
||||||
val parametrizedMethod = reference.fastResolveFor(method)
|
val sourceProviders = reference.multiResolve(false)
|
||||||
if (parametrizedMethod !is PsiMethod) {
|
val sourceProvider = sourceProviders
|
||||||
|
.mapNotNull { it as? PsiMethodSourceResolveResult }
|
||||||
|
.firstNotNullOfOrNull { it.getSourceMethodForClass(method.javaPsi.containingClass ?: return) }
|
||||||
|
if (sourceProvider == null) {
|
||||||
return checkAbsentSourceProvider(containingClass, attributeValue, reference.value, method)
|
return checkAbsentSourceProvider(containingClass, attributeValue, reference.value, method)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val uSourceProvider = parametrizedMethod.toUElementOfType<UMethod>() ?: return
|
val uSourceProvider = sourceProvider.toUElementOfType<UMethod>() ?: return
|
||||||
return checkSourceProvider(uSourceProvider, containingClass, attributeValue, method)
|
return checkSourceProvider(uSourceProvider, containingClass, attributeValue, method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -576,6 +580,12 @@ private class JUnitMalformedSignatureVisitor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun PsiMethodSourceResolveResult.getSourceMethodForClass(owner: PsiClass): PsiMethod? {
|
||||||
|
val method = element as? PsiMethod ?: return null
|
||||||
|
if (owners.isEmpty()) return method // direct link
|
||||||
|
return owner.findMethodBySignature(method, true)
|
||||||
|
}
|
||||||
|
|
||||||
private fun checkAbsentSourceProvider(
|
private fun checkAbsentSourceProvider(
|
||||||
containingClass: PsiClass, attributeValue: PsiElement, sourceProviderName: String, method: UMethod
|
containingClass: PsiClass, attributeValue: PsiElement, sourceProviderName: String, method: UMethod
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import com.intellij.psi.impl.source.resolve.ResolveCache
|
|||||||
import com.intellij.psi.search.searches.AnnotatedElementsSearch
|
import com.intellij.psi.search.searches.AnnotatedElementsSearch
|
||||||
import com.intellij.psi.search.searches.ClassInheritorsSearch
|
import com.intellij.psi.search.searches.ClassInheritorsSearch
|
||||||
import com.intellij.psi.util.ClassUtil
|
import com.intellij.psi.util.ClassUtil
|
||||||
import com.intellij.psi.util.PsiUtil
|
|
||||||
import org.jetbrains.uast.*
|
import org.jetbrains.uast.*
|
||||||
|
|
||||||
abstract class BaseJunitAnnotationReference(
|
abstract class BaseJunitAnnotationReference(
|
||||||
@@ -33,10 +32,13 @@ abstract class BaseJunitAnnotationReference(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun isReferenceTo(element: PsiElement): Boolean {
|
override fun isReferenceTo(element: PsiElement): Boolean {
|
||||||
val literal = getElement().toUElement(UExpression::class.java) ?: return false
|
val results: Array<ResolveResult> = multiResolve(false)
|
||||||
val scope = element.toUElement(UMethod::class.java)?.getParentOfType(UClass::class.java) ?: return false
|
for (result in results) {
|
||||||
return directLink(literal, scope) == element ||
|
if (element == result.getElement()) {
|
||||||
fastResolveFor(literal, scope) == element
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun resolve(): PsiElement? {
|
override fun resolve(): PsiElement? {
|
||||||
@@ -44,12 +46,6 @@ abstract class BaseJunitAnnotationReference(
|
|||||||
return if (results.size == 1) results[0].element else null
|
return if (results.size == 1) results[0].element else null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun filteredMethod(clazzMethods: Array<PsiMethod>, uClass: UClass, uMethod: UMethod?): PsiMethod? {
|
|
||||||
return clazzMethods.firstOrNull { method ->
|
|
||||||
hasNoStaticProblem(method, uClass, uMethod)
|
|
||||||
} ?: if (clazzMethods.isEmpty()) null else clazzMethods.first()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getVariants(): Array<Any> {
|
override fun getVariants(): Array<Any> {
|
||||||
val myLiteral = element.toUElement(UExpression::class.java) ?: return emptyArray()
|
val myLiteral = element.toUElement(UExpression::class.java) ?: return emptyArray()
|
||||||
val topLevelClass = myLiteral.getParentOfType(UClass::class.java) ?: return emptyArray()
|
val topLevelClass = myLiteral.getParentOfType(UClass::class.java) ?: return emptyArray()
|
||||||
@@ -87,33 +83,32 @@ abstract class BaseJunitAnnotationReference(
|
|||||||
val methodName = StringUtil.getShortName(string, '#')
|
val methodName = StringUtil.getShortName(string, '#')
|
||||||
if (methodName.isEmpty()) return null
|
if (methodName.isEmpty()) return null
|
||||||
val directClass = ClassUtil.findPsiClass(scope.javaPsi.manager, className, null, false, scope.javaPsi.resolveScope) ?: return null
|
val directClass = ClassUtil.findPsiClass(scope.javaPsi.manager, className, null, false, scope.javaPsi.resolveScope) ?: return null
|
||||||
val directUClass = directClass.toUElement(UClass::class.java) ?: return null
|
return directClass.findMethodsByName(methodName, false).firstOrNull()
|
||||||
return filteredMethod(directClass.findMethodsByName(methodName, false), directUClass, literal.getParentOfType(UMethod::class.java))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fastResolveFor(literal: UExpression, scope: UClass): PsiElement? {
|
private fun fastResolveFor(literal: UExpression, scope: UClass): Set<PsiMethod> {
|
||||||
val methodName = literal.evaluate() as String? ?: return null
|
val methodName = literal.evaluate() as String? ?: return setOf()
|
||||||
val psiClazz = scope.javaPsi
|
val psiClazz = scope.javaPsi
|
||||||
val clazzMethods = psiClazz.findMethodsByName(methodName, true)
|
val clazzMethods = psiClazz.findMethodsByName(methodName, true)
|
||||||
if (clazzMethods.isEmpty() && (scope.isInterface || PsiUtil.isAbstractClass(psiClazz))) {
|
|
||||||
val methods = ClassInheritorsSearch.search(psiClazz, psiClazz.resolveScope, false)
|
val methods = ClassInheritorsSearch.search(psiClazz, psiClazz.resolveScope, true)
|
||||||
.findAll()
|
.findAll()
|
||||||
.flatMap { aClazz -> aClazz.findMethodsByName(methodName, false).toList() }
|
.flatMap { aClazz -> aClazz.findMethodsByName(methodName, true).toList() }
|
||||||
return filteredMethod(methods.toTypedArray(), scope, literal.getParentOfType(UMethod::class.java))
|
.toMutableSet()
|
||||||
}
|
methods.addAll(clazzMethods)
|
||||||
return filteredMethod(clazzMethods, scope, literal.getParentOfType(UMethod::class.java))
|
return methods
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param testMethod test method marked with JUnit annotation
|
* @param testMethod test method marked with JUnit annotation
|
||||||
* @return the method referenced from the annotation
|
* @return the method referenced from the annotation
|
||||||
*/
|
*/
|
||||||
fun fastResolveFor(testMethod: UMethod): PsiElement? {
|
private fun fastResolveFor(testMethod: UMethod): Set<PsiMethod> {
|
||||||
val literal = element.toUElement(UExpression::class.java) ?: return null
|
val literal = element.toUElement(UExpression::class.java) ?: return setOf()
|
||||||
val scope = literal.getParentOfType(UClass::class.java) ?: return null
|
val scope = literal.getParentOfType(UClass::class.java) ?: return setOf()
|
||||||
val directLink = directLink(literal, scope)
|
val directLink = directLink(literal, scope)
|
||||||
if (directLink != null) return directLink
|
if (directLink != null) return setOf(directLink)
|
||||||
var currentClass = testMethod.getParentOfType(UClass::class.java) ?: return null
|
val currentClass = testMethod.getParentOfType(UClass::class.java) ?: return setOf()
|
||||||
return fastResolveFor(literal, currentClass)
|
return fastResolveFor(literal, currentClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,13 +126,14 @@ abstract class BaseJunitAnnotationReference(
|
|||||||
val literal = ref.element.toUElement(UExpression::class.java) ?: return ResolveResult.EMPTY_ARRAY
|
val literal = ref.element.toUElement(UExpression::class.java) ?: return ResolveResult.EMPTY_ARRAY
|
||||||
val uClass = literal.getParentOfType(UClass::class.java) ?: return ResolveResult.EMPTY_ARRAY
|
val uClass = literal.getParentOfType(UClass::class.java) ?: return ResolveResult.EMPTY_ARRAY
|
||||||
val directLink = ref.directLink(literal, uClass)
|
val directLink = ref.directLink(literal, uClass)
|
||||||
if (directLink != null) return arrayOf(PsiElementResolveResult(directLink))
|
if (directLink != null) return arrayOf(PsiMethodSourceResolveResult(directLink, listOf()))
|
||||||
|
|
||||||
val method = literal.getParentOfType(UMethod::class.java)
|
val method = literal.getParentOfType(UMethod::class.java)
|
||||||
if (method != null) { // direct annotation
|
if (method != null) { // direct annotation
|
||||||
val resolved = ref.fastResolveFor(method)
|
val owners = method.javaPsi.containingClass?.let { listOf(it) } ?: emptyList()
|
||||||
return if (resolved is PsiMethod) arrayOf(PsiElementResolveResult(resolved)) else ResolveResult.EMPTY_ARRAY
|
return ref.fastResolveFor(method).map { PsiMethodSourceResolveResult(it, owners) }.toTypedArray()
|
||||||
} else if (uClass.isAnnotationType) { // inherited annotation from another annotation
|
}
|
||||||
|
else if (uClass.isAnnotationType) { // inherited annotation from another annotation
|
||||||
val scope = uClass.sourcePsi?.resolveScope ?: ref.element.resolveScope
|
val scope = uClass.sourcePsi?.resolveScope ?: ref.element.resolveScope
|
||||||
val process = ArrayDeque<PsiClass>()
|
val process = ArrayDeque<PsiClass>()
|
||||||
val processed = mutableSetOf<PsiClass>()
|
val processed = mutableSetOf<PsiClass>()
|
||||||
@@ -158,9 +154,12 @@ abstract class BaseJunitAnnotationReference(
|
|||||||
.mapNotNull { method -> method.toUElement(UMethod::class.java) }
|
.mapNotNull { method -> method.toUElement(UMethod::class.java) }
|
||||||
.mapNotNull { method -> method.getParentOfType(UClass::class.java) }
|
.mapNotNull { method -> method.getParentOfType(UClass::class.java) }
|
||||||
.distinct() // process only classes
|
.distinct() // process only classes
|
||||||
.mapNotNull { clazz -> ref.fastResolveFor(literal, clazz) }
|
.map{ clazz -> clazz to ref.fastResolveFor(literal, clazz) }
|
||||||
.map { method -> PsiElementResolveResult(method) }.toTypedArray()
|
.flatMap { (clazz, methods) -> methods.map { method -> method to clazz } }
|
||||||
} else {
|
.groupBy({ it.first }, { it.second })
|
||||||
|
.map { (method, classes) -> PsiMethodSourceResolveResult(method, classes) }.toTypedArray()
|
||||||
|
}
|
||||||
|
else {
|
||||||
return ResolveResult.EMPTY_ARRAY
|
return ResolveResult.EMPTY_ARRAY
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||||
|
package com.intellij.execution.junit.references
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiClass
|
||||||
|
import com.intellij.psi.PsiElementResolveResult
|
||||||
|
import com.intellij.psi.PsiMethod
|
||||||
|
|
||||||
|
class PsiMethodSourceResolveResult(method: PsiMethod, val owners: List<PsiClass>): PsiElementResolveResult(method) {
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user