Partial body resolve works for local Nothing functions + does not go inside local functions and classes

This commit is contained in:
Valentin Kipyatkov
2014-11-19 20:03:31 +03:00
parent b22233d378
commit 8010c0f09d
15 changed files with 118 additions and 33 deletions
@@ -391,3 +391,6 @@ public fun Call.isSafeCall(): Boolean {
}
public fun Call.isExplicitSafeCall(): Boolean = getCallOperationNode()?.getElementType() == JetTokens.SAFE_ACCESS
public fun JetTypeReference?.isProbablyNothing(): Boolean
= (this?.getTypeElement() as? JetUserType)?.getReferencedName() == "Nothing"
@@ -24,6 +24,7 @@ import com.intellij.util.io.StringRef;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.psi.psiUtil.PsiUtilPackage;
import org.jetbrains.jet.lang.psi.stubs.KotlinFunctionStub;
import org.jetbrains.jet.lang.psi.stubs.impl.KotlinFunctionStubImpl;
import org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils;
@@ -46,7 +47,7 @@ public class JetFunctionElementType extends JetStubElementType<KotlinFunctionStu
boolean hasBody = psi.hasBody();
return new KotlinFunctionStubImpl(parentStub, StringRef.fromString(psi.getName()), isTopLevel, fqName,
isExtension, hasBlockBody, hasBody, psi.hasTypeParameterListBeforeFunctionName(),
ElementsPackage.isProbablyNothing(psi.getTypeReference()));
PsiUtilPackage.isProbablyNothing(psi.getTypeReference()));
}
@Override
@@ -24,6 +24,7 @@ import com.intellij.util.io.StringRef;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetProperty;
import org.jetbrains.jet.lang.psi.psiUtil.PsiUtilPackage;
import org.jetbrains.jet.lang.psi.stubs.KotlinPropertyStub;
import org.jetbrains.jet.lang.psi.stubs.impl.KotlinPropertyStubImpl;
import org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils;
@@ -47,7 +48,7 @@ public class JetPropertyElementType extends JetStubElementType<KotlinPropertyStu
psi.isVar(), psi.isTopLevel(), psi.hasDelegate(),
psi.hasDelegateExpression(), psi.hasInitializer(),
psi.getReceiverTypeReference() != null, psi.getTypeReference() != null,
ElementsPackage.isProbablyNothing(psi.getTypeReference()),
PsiUtilPackage.isProbablyNothing(psi.getTypeReference()),
ResolveSessionUtils.safeFqNameForLazyResolve(psi)
);
}
@@ -1,23 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.lang.psi.stubs.elements
import org.jetbrains.jet.lang.psi.JetUserType
import org.jetbrains.jet.lang.psi.JetTypeReference
fun JetTypeReference?.isProbablyNothing()
= (this?.getTypeElement() as? JetUserType)?.getReferencedName() == "Nothing"
@@ -26,6 +26,9 @@ import java.util.HashMap
import com.intellij.psi.PsiElement
import org.jetbrains.jet.JetNodeTypes
import org.jetbrains.jet.lang.psi.psiUtil.isAncestor
import org.jetbrains.jet.lang.psi.psiUtil.isProbablyNothing
//TODO: do resolve anonymous object's body
class PartialBodyResolveFilter(
elementToResolve: JetElement,
@@ -35,12 +38,27 @@ class PartialBodyResolveFilter(
private val statementsToResolve = HashSet<JetExpression>()
private val processedBlocks = HashSet<JetBlockExpression>()
private val nothingFunctionNames = probablyNothingCallableNamesService.functionNames()
private val nothingFunctionNames = HashSet(probablyNothingCallableNamesService.functionNames())
private val nothingPropertyNames = probablyNothingCallableNamesService.propertyNames()
;{
assert(body.isAncestor(elementToResolve, strict = false))
body.accept(object : JetVisitorVoid(){
override fun visitNamedFunction(function: JetNamedFunction) {
super.visitNamedFunction(function)
if (function.getTypeReference().isProbablyNothing()) {
nothingFunctionNames.add(function.getName())
}
}
override fun visitElement(element: PsiElement) {
element.acceptChildren(this)
}
})
addStatementsToResolve(elementToResolve)
}
@@ -54,8 +72,7 @@ class PartialBodyResolveFilter(
private fun addStatementsToResolve(element: JetElement) {
if (element == body) return
val parent = element.getParent() as? JetElement
?: return
val parent = element.getParent() as? JetElement ?: return
if (parent is JetBlockExpression) {
processBlock(parent)
@@ -67,6 +84,7 @@ class PartialBodyResolveFilter(
for (statement in element.siblings(forward = false, withItself = false)) {
if (statement !is JetExpression) continue
if (statement is JetClassBody) continue
val smartCastPlaces = potentialSmartCastPlaces(statement)
if (!smartCastPlaces.isEmpty()) {
@@ -312,15 +330,15 @@ class PartialBodyResolveFilter(
return result
}
private abstract class ControlFlowVisitor : JetVisitorVoid() {
private inner abstract class ControlFlowVisitor : JetVisitorVoid() {
override fun visitJetElement(element: JetElement) {
if (element.noControlFlowInside()) return
element.acceptChildren(this)
}
private fun JetElement.noControlFlowInside() = this is JetFunction || this is JetClass || this is JetClassBody
}
private fun JetElement.noControlFlowInside() = this is JetFunction || this is JetClass || this is JetClassBody
private fun MutableSet<JetExpression>.addStatementsForPlaces(thisStatement: JetExpression, places: Collection<JetExpression>) {
@PlacesLoop
for (place in places) {
@@ -99,7 +99,6 @@ public class ResolveElementCache extends ElementResolver {
set.addAll(hardcodedNames);
set.addAll(indexedNames);
return set;
//TODO: what about local declarations?
}
@NotNull
@@ -0,0 +1,2 @@
Resolve target: value-parameter val p: kotlin.String?
Skipped statements:
@@ -0,0 +1,22 @@
open class C(p: Int) {
open fun f(){}
}
fun foo(p: String?) {
val o = object : Runnable {
override fun run() {
if (p == null) return
print(p.size)
}
}
val c = object : C(p!!.size) {
override fun f() {
super.f()
if (p == null) return
print(p.size)
}
}
<caret>p?.size
}
@@ -0,0 +1,2 @@
Resolve target: value-parameter val p: kotlin.String?
Skipped statements:
@@ -0,0 +1,11 @@
fun foo(p: String?) {
class LocalClass {
fun f(): String? {
if (p == null) return null
print(p.size)
return ""
}
}
<caret>p?.size
}
@@ -0,0 +1,5 @@
Resolve target: value-parameter val p: kotlin.String?
Skipped statements:
if (p == null) return null
print(p.size)
return ""
@@ -0,0 +1,9 @@
fun foo(p: String?) {
fun local(): String? {
if (p == null) return null
print(p.size)
return ""
}
<caret>p?.size
}
@@ -0,0 +1,2 @@
Resolve target: value-parameter val p: kotlin.String? smart-casted to kotlin.String
Skipped statements:
@@ -0,0 +1,10 @@
fun foo(p: String?, p1: Any?) {
if (p1 == null) return
fun localError(): Nothing = throw Exception()
if (p == null) {
localError()
}
<caret>p.size
}
@@ -19,7 +19,6 @@ package org.jetbrains.jet.resolve;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.jet.JUnit3RunnerWithInners;
import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.test.InnerTestClasses;
import org.jetbrains.jet.test.TestMetadata;
import org.junit.runner.RunWith;
@@ -36,6 +35,12 @@ public class PartialBodyResolveTestGenerated extends AbstractPartialBodyResolveT
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/resolve/partialBodyResolve"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("AnonymousObjects.kt")
public void testAnonymousObjects() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/AnonymousObjects.kt");
doTest(fileName);
}
@TestMetadata("As.kt")
public void testAs() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/As.kt");
@@ -234,6 +239,24 @@ public class PartialBodyResolveTestGenerated extends AbstractPartialBodyResolveT
doTest(fileName);
}
@TestMetadata("LocalClass.kt")
public void testLocalClass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/LocalClass.kt");
doTest(fileName);
}
@TestMetadata("LocalFun.kt")
public void testLocalFun() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/LocalFun.kt");
doTest(fileName);
}
@TestMetadata("LocalNothingFun.kt")
public void testLocalNothingFun() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/LocalNothingFun.kt");
doTest(fileName);
}
@TestMetadata("Simple.kt")
public void testSimple() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/Simple.kt");