Support contracts in PartialBodyResolveFilter
Previously, PartialBodyResolveFilter didn't know about contracts and was
filtering out calls of such functions, leading to unstable completion in
cases like that:
fun test(x: Any?) {
require(x is String)
x.<caret>
}
However, PartialBodyResolveFilter works by pure PSI, while to determine
if function has a contract we have to resolve it.
To solve it, we do something very similar to what has been done with
Nothin-returning functions: introduce
KotlinProbablyContractedFunctionShortNameIndex, which collects all
function which *may* have a contract during indexing.
^KT-25275 Fixed
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.resolve.lazy
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiRecursiveElementVisitor
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -38,6 +39,7 @@ class PartialBodyResolveFilter(
|
||||
private val statementMarks = StatementMarks()
|
||||
|
||||
private val globalProbablyNothingCallableNames = ProbablyNothingCallableNames.getInstance(declaration.project)
|
||||
private val globalProbablyContractedCallableNames = ProbablyContractedCallableNames.getInstance(declaration.project)
|
||||
|
||||
private val contextNothingFunctionNames = HashSet<String>()
|
||||
private val contextNothingVariableNames = HashSet<String>()
|
||||
@@ -169,6 +171,19 @@ class PartialBodyResolveFilter(
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitCallExpression(expression: KtCallExpression) {
|
||||
super.visitCallExpression(expression)
|
||||
|
||||
val nameReference = expression.calleeExpression as? KtNameReferenceExpression ?: return
|
||||
if (!globalProbablyContractedCallableNames.isProbablyContractedCallableName(nameReference.getReferencedName())) return
|
||||
|
||||
val mentionedSmartCastName = expression.findMentionedName(filter)
|
||||
|
||||
if (mentionedSmartCastName != null) {
|
||||
addPlace(mentionedSmartCastName, expression)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitBinaryWithTypeRHSExpression(expression: KtBinaryExpressionWithTypeRHS) {
|
||||
expression.acceptChildren(this)
|
||||
|
||||
@@ -259,6 +274,25 @@ class PartialBodyResolveFilter(
|
||||
return map
|
||||
}
|
||||
|
||||
private fun KtExpression.findMentionedName(filter: (SmartCastName) -> Boolean): SmartCastName? {
|
||||
var foundMentionedName: SmartCastName? = null
|
||||
|
||||
val visitor = object : PsiRecursiveElementVisitor() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
if (foundMentionedName != null) return
|
||||
|
||||
if (element !is KtSimpleNameExpression) super.visitElement(element)
|
||||
if (element !is KtExpression) return
|
||||
|
||||
element.smartCastExpressionName()?.takeIf(filter)?.let { foundMentionedName = it }
|
||||
}
|
||||
}
|
||||
|
||||
accept(visitor)
|
||||
|
||||
return foundMentionedName
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns names of expressions that would possibly be smart cast
|
||||
* in then (first component) and else (second component)
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2010-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/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.lazy
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.project.Project
|
||||
|
||||
interface ProbablyContractedCallableNames {
|
||||
fun isProbablyContractedCallableName(name: String): Boolean
|
||||
|
||||
companion object {
|
||||
fun getInstance(project: Project): ProbablyContractedCallableNames =
|
||||
ServiceManager.getService(project, ProbablyContractedCallableNames::class.java)!!
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user