Fixed bug in partial body resolve

This commit is contained in:
Valentin Kipyatkov
2015-02-19 19:21:35 +03:00
parent db987eedee
commit 27f5d71e4f
6 changed files with 72 additions and 15 deletions
@@ -94,14 +94,14 @@ class PartialBodyResolveFilter(
if (statement is JetNamedDeclaration) {
val name = statement.getName()
if (name != null && nameFilter.accepts(name)) {
if (name != null && nameFilter(name)) {
statementMarks.mark(statement, MarkLevel.NEED_REFERENCE_RESOLVE)
}
}
else if (statement is JetMultiDeclaration) {
if (statement.getEntries().any {
val name = it.getName()
name != null && nameFilter.accepts(name)
name != null && nameFilter(name)
}) {
statementMarks.mark(statement, MarkLevel.NEED_REFERENCE_RESOLVE)
}
@@ -118,7 +118,7 @@ class PartialBodyResolveFilter(
updateNameFilter()
if (!nameFilter.isEmpty) {
val smartCastPlaces = potentialSmartCastPlaces(statement, { it.identifiers().all { nameFilter.accepts(it) } })
val smartCastPlaces = potentialSmartCastPlaces(statement, { it.affectsNames(nameFilter) })
if (!smartCastPlaces.isEmpty()) {
//TODO: do we really need correct resolve for ALL smart cast places?
smartCastPlaces.values()
@@ -179,7 +179,7 @@ class PartialBodyResolveFilter(
override fun visitBinaryWithTypeRHSExpression(expression: JetBinaryExpressionWithTypeRHS) {
expression.acceptChildren(this)
if (expression.getOperationReference()?.getReferencedNameElementType() == JetTokens.AS_KEYWORD) {
if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.AS_KEYWORD) {
addIfCanBeSmartCast(expression.getLeft())
}
}
@@ -262,7 +262,7 @@ class PartialBodyResolveFilter(
override fun visitIsExpression(expression: JetIsExpression) {
expression.acceptChildren(this)
result.addIfNotNull(expression.getLeftHandSide()?.smartCastExpressionName())
result.addIfNotNull(expression.getLeftHandSide().smartCastExpressionName())
}
})
return result
@@ -379,18 +379,25 @@ class PartialBodyResolveFilter(
private fun JetElement.noControlFlowInside() = this is JetFunction || this is JetClass || this is JetClassBody
}
private data class SmartCastName(val receiverName: SmartCastName?, val selectorName: String) {
override fun toString(): String = if (receiverName != null) receiverName.toString() + "." + selectorName else selectorName
private data class SmartCastName(
private val receiverName: SmartCastName?,
private val selectorName: String? /* null means "this" (and receiverName should be null */
) {
{
if (selectorName == null) {
assert(receiverName == null, "selectorName is allowed to be null only when receiverName is also null (which means 'this')")
}
}
fun identifiers(): Collection<String> {
return if (receiverName != null)
receiverName.identifiers() + listOf(selectorName)
else
listOf(selectorName)
override fun toString(): String = if (receiverName != null) receiverName.toString() + "." + selectorName else selectorName ?: "this"
fun affectsNames(nameFilter: (String) -> Boolean): Boolean {
if (selectorName == null) return true
if (!nameFilter(selectorName)) return false
return receiverName == null || receiverName.affectsNames(nameFilter)
}
}
//TODO: this can be smart-cast too!
private fun JetExpression.smartCastExpressionName(): SmartCastName? {
return when (this) {
is JetSimpleNameExpression -> SmartCastName(null, this.getReferencedName())
@@ -406,15 +413,17 @@ class PartialBodyResolveFilter(
return SmartCastName(receiverName, selectorName)
}
is JetThisExpression -> SmartCastName(null, null)
else -> null
}
}
//TODO: declarations with special names (e.g. "get")
private class NameFilter {
private class NameFilter : (String) -> Boolean {
private var names: MutableSet<String>? = HashSet()
fun accepts(name: String) = names == null || name in names!!
override fun invoke(name: String) = names == null || name in names!!
val isEmpty: Boolean
get() = names?.isEmpty() ?: false
@@ -0,0 +1,10 @@
Resolve target: fun foo(): kotlin.Unit
----------------------------------------------
class C {
fun foo(){}
}
fun Any.f() {
if (this !is C) return
<caret>foo()
}
@@ -0,0 +1,8 @@
class C {
fun foo(){}
}
fun Any.f() {
if (this !is C) return
<caret>foo()
}
@@ -0,0 +1,10 @@
Resolve target: fun foo(): kotlin.Unit
----------------------------------------------
class C {
fun foo(){}
}
fun Any.f() {
if (this !is C) return
this.<caret>foo()
}
@@ -0,0 +1,8 @@
class C {
fun foo(){}
}
fun Any.f() {
if (this !is C) return
this.<caret>foo()
}
@@ -360,6 +360,18 @@ public class PartialBodyResolveTestGenerated extends AbstractPartialBodyResolveT
doTest(fileName);
}
@TestMetadata("SmartCastOfThis1.kt")
public void testSmartCastOfThis1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/SmartCastOfThis1.kt");
doTest(fileName);
}
@TestMetadata("SmartCastOfThis2.kt")
public void testSmartCastOfThis2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/SmartCastOfThis2.kt");
doTest(fileName);
}
@TestMetadata("SmartCastPointsResolveRequired1.kt")
public void testSmartCastPointsResolveRequired1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/SmartCastPointsResolveRequired1.kt");