mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Handle cases when operator keyword is implicitly inherited
Relates to #KTIJ-18868 GitOrigin-RevId: 815c75723c63daa8646eabcda4d31608336894cb
This commit is contained in:
committed by
intellij-monorepo-bot
parent
b6c313031d
commit
3a3f672cd5
+14
-5
@@ -16,14 +16,13 @@ import com.intellij.util.Processor
|
||||
import com.intellij.util.indexing.FileBasedIndex
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.scriptDefinitionExists
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtImportDirective
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName as getKotlinFqNameOriginal
|
||||
|
||||
infix fun SearchScope.and(otherScope: SearchScope): SearchScope = intersectWith(otherScope)
|
||||
@@ -144,4 +143,14 @@ fun PsiReference.isImportUsage(): Boolean =
|
||||
level = DeprecationLevel.ERROR,
|
||||
replaceWith = ReplaceWith("getKotlinFqName()", "org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName")
|
||||
)
|
||||
fun PsiElement.getKotlinFqName(): FqName? = getKotlinFqNameOriginal()
|
||||
fun PsiElement.getKotlinFqName(): FqName? = getKotlinFqNameOriginal()
|
||||
|
||||
fun KtElement.isPotentiallyOperator(): Boolean {
|
||||
val namedFunction = safeAs<KtNamedFunction>() ?: return false
|
||||
if (namedFunction.hasModifier(KtTokens.OPERATOR_KEYWORD)) return true
|
||||
// operator modifier could be omitted for overriding function
|
||||
if (!namedFunction.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return false
|
||||
|
||||
// TODO: it's fast PSI-based check, a proper check requires call to resolveDeclarationWithParents() that is not frontend-independent
|
||||
return true
|
||||
}
|
||||
+6
-6
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.forc
|
||||
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.getReceiverTypeSearcherInfo
|
||||
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
|
||||
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinRequestResultProcessor
|
||||
import org.jetbrains.kotlin.idea.search.isPotentiallyOperator
|
||||
import org.jetbrains.kotlin.idea.search.restrictToKotlinSources
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.ExpressionsOfTypeProcessor
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.ExpressionsOfTypeProcessor.Companion.logPresentation
|
||||
@@ -119,8 +120,7 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
if (!options.searchForOperatorConventions) return null
|
||||
|
||||
// Java has no operator modifier
|
||||
val operator = declaration !is KtElement ||
|
||||
declaration.safeAs<KtModifierListOwner>()?.hasModifier(KtTokens.OPERATOR_KEYWORD) == true
|
||||
val operator = declaration !is KtElement || declaration.isPotentiallyOperator()
|
||||
|
||||
val binaryOp = OperatorConventions.BINARY_OPERATION_NAMES.inverse()[name]
|
||||
val assignmentOp = OperatorConventions.ASSIGNMENT_OPERATIONS.inverse()[name]
|
||||
@@ -148,7 +148,7 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
operator && name == OperatorNameConventions.SET ->
|
||||
IndexingOperatorReferenceSearcher(declaration, searchScope, consumer, optimizer, options, isSet = true)
|
||||
|
||||
name == OperatorNameConventions.CONTAINS ->
|
||||
operator && name == OperatorNameConventions.CONTAINS ->
|
||||
ContainsOperatorReferenceSearcher(declaration, searchScope, consumer, optimizer, options)
|
||||
|
||||
name == OperatorNameConventions.EQUALS ->
|
||||
@@ -161,7 +161,7 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
options
|
||||
)
|
||||
|
||||
name == OperatorNameConventions.COMPARE_TO ->
|
||||
operator && name == OperatorNameConventions.COMPARE_TO ->
|
||||
BinaryOperatorReferenceSearcher(
|
||||
declaration,
|
||||
listOf(KtTokens.LT, KtTokens.GT, KtTokens.LTEQ, KtTokens.GTEQ),
|
||||
@@ -171,10 +171,10 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
options
|
||||
)
|
||||
|
||||
name == OperatorNameConventions.ITERATOR ->
|
||||
operator && name == OperatorNameConventions.ITERATOR ->
|
||||
IteratorOperatorReferenceSearcher(declaration, searchScope, consumer, optimizer, options)
|
||||
|
||||
name == OperatorNameConventions.GET_VALUE || name == OperatorNameConventions.SET_VALUE || name == OperatorNameConventions.PROVIDE_DELEGATE ->
|
||||
operator && (name == OperatorNameConventions.GET_VALUE || name == OperatorNameConventions.SET_VALUE || name == OperatorNameConventions.PROVIDE_DELEGATE) ->
|
||||
PropertyDelegationOperatorReferenceSearcher(declaration, searchScope, consumer, optimizer, options)
|
||||
|
||||
else -> null
|
||||
|
||||
+15
-1
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator
|
||||
import org.jetbrains.kotlin.idea.core.copied
|
||||
import org.jetbrains.kotlin.idea.highlighter.markers.resolveDeclarationWithParents
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
import org.jetbrains.kotlin.idea.refactoring.explicateAsText
|
||||
import org.jetbrains.kotlin.idea.refactoring.getThisLabelName
|
||||
@@ -371,7 +372,7 @@ internal fun checkNewNameUsagesRetargeting(
|
||||
return
|
||||
}
|
||||
|
||||
val operator = declaration.safeAs<KtModifierListOwner>()?.hasModifier(KtTokens.OPERATOR_KEYWORD) == true
|
||||
val operator = declaration.isOperator()
|
||||
|
||||
for (candidateDescriptor in declaration.getResolutionScope().getRelevantDescriptors(declaration, newName)) {
|
||||
val candidate =
|
||||
@@ -388,3 +389,16 @@ internal fun checkNewNameUsagesRetargeting(
|
||||
usages.filterIsInstanceTo<KtResolvableCollisionUsageInfo, MutableList<UsageInfo>>(newUsages)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun KtElement.isOperator(): Boolean {
|
||||
val namedFunction = safeAs<KtNamedFunction>() ?: return false
|
||||
if (namedFunction.hasModifier(KtTokens.OPERATOR_KEYWORD)) return true
|
||||
// operator modifier could be omitted for overriding function
|
||||
if (!namedFunction.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return false
|
||||
|
||||
val resolveWithParents = resolveDeclarationWithParents(this as KtNamedFunction)
|
||||
return resolveWithParents.overriddenDescriptors.any {
|
||||
val psi = it.source.getPsi() ?: return@any false
|
||||
psi !is KtElement || psi.safeAs<KtNamedFunction>()?.hasModifier(KtTokens.OPERATOR_KEYWORD) == true
|
||||
}
|
||||
}
|
||||
+5
@@ -116,6 +116,11 @@ public abstract class FindUsagesTestGenerated extends AbstractFindUsagesTest {
|
||||
runTest("testData/findUsages/kotlin/conventions/invokeInObject.0.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("invokeInheritance.0.kt")
|
||||
public void testInvokeInheritance() throws Exception {
|
||||
runTest("testData/findUsages/kotlin/conventions/invokeInheritance.0.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("invokeWithVarArg.0.kt")
|
||||
public void testInvokeWithVarArg() throws Exception {
|
||||
runTest("testData/findUsages/kotlin/conventions/invokeWithVarArg.0.kt");
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// PSI_ELEMENT: org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
// OPTIONS: usages
|
||||
package pack
|
||||
|
||||
open class Base {
|
||||
open operator fun invoke(){}
|
||||
}
|
||||
|
||||
class Child: Base() {
|
||||
override fun <caret>invoke(){}
|
||||
}
|
||||
|
||||
fun test() {
|
||||
val c = Child()
|
||||
c()
|
||||
c.invoke()
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
Checked type of c
|
||||
Resolved Child()
|
||||
Resolved c()
|
||||
Searched references to c in non-Java files
|
||||
Searched references to pack.Base
|
||||
Searched references to pack.Child
|
||||
Used plain search of pack.Base.invoke() in LocalSearchScope:
|
||||
CLASS:Base
|
||||
CLASS:Child
|
||||
Used plain search of pack.Child.invoke() in LocalSearchScope:
|
||||
CLASS:Child
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
Function call 16 c.invoke()
|
||||
Function call 16 c.invoke()
|
||||
Implicit 'invoke' 15 c()
|
||||
Reference in New Issue
Block a user