From 8010c0f09dcee0d408ee51f896ce6bc29a34d115 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 19 Nov 2014 20:03:31 +0300 Subject: [PATCH] Partial body resolve works for local Nothing functions + does not go inside local functions and classes --- .../jet/lang/psi/psiUtil/jetPsiUtil.kt | 3 ++ .../elements/JetFunctionElementType.java | 3 +- .../elements/JetPropertyElementType.java | 3 +- .../jet/lang/psi/stubs/elements/Util.kt | 23 -------------- .../resolve/lazy/PartialBodyResolveFilter.kt | 30 +++++++++++++++---- .../plugin/project/ResolveElementCache.java | 1 - .../partialBodyResolve/AnonymousObjects.dump | 2 ++ .../partialBodyResolve/AnonymousObjects.kt | 22 ++++++++++++++ .../partialBodyResolve/LocalClass.dump | 2 ++ .../resolve/partialBodyResolve/LocalClass.kt | 11 +++++++ .../resolve/partialBodyResolve/LocalFun.dump | 5 ++++ .../resolve/partialBodyResolve/LocalFun.kt | 9 ++++++ .../partialBodyResolve/LocalNothingFun.dump | 2 ++ .../partialBodyResolve/LocalNothingFun.kt | 10 +++++++ .../PartialBodyResolveTestGenerated.java | 25 +++++++++++++++- 15 files changed, 118 insertions(+), 33 deletions(-) delete mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/Util.kt create mode 100644 idea/testData/resolve/partialBodyResolve/AnonymousObjects.dump create mode 100644 idea/testData/resolve/partialBodyResolve/AnonymousObjects.kt create mode 100644 idea/testData/resolve/partialBodyResolve/LocalClass.dump create mode 100644 idea/testData/resolve/partialBodyResolve/LocalClass.kt create mode 100644 idea/testData/resolve/partialBodyResolve/LocalFun.dump create mode 100644 idea/testData/resolve/partialBodyResolve/LocalFun.kt create mode 100644 idea/testData/resolve/partialBodyResolve/LocalNothingFun.dump create mode 100644 idea/testData/resolve/partialBodyResolve/LocalNothingFun.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt b/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt index 6a3dad45d4a..9f01f471aec 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt @@ -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" \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFunctionElementType.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFunctionElementType.java index c7f3e7afc7a..ca214698dbf 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFunctionElementType.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFunctionElementType.java @@ -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() private val processedBlocks = HashSet() - 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.addStatementsForPlaces(thisStatement: JetExpression, places: Collection) { @PlacesLoop for (place in places) { diff --git a/idea/idea-analysis/src/org/jetbrains/jet/plugin/project/ResolveElementCache.java b/idea/idea-analysis/src/org/jetbrains/jet/plugin/project/ResolveElementCache.java index a7d534083cf..601add33fdc 100644 --- a/idea/idea-analysis/src/org/jetbrains/jet/plugin/project/ResolveElementCache.java +++ b/idea/idea-analysis/src/org/jetbrains/jet/plugin/project/ResolveElementCache.java @@ -99,7 +99,6 @@ public class ResolveElementCache extends ElementResolver { set.addAll(hardcodedNames); set.addAll(indexedNames); return set; - //TODO: what about local declarations? } @NotNull diff --git a/idea/testData/resolve/partialBodyResolve/AnonymousObjects.dump b/idea/testData/resolve/partialBodyResolve/AnonymousObjects.dump new file mode 100644 index 00000000000..8671dde7711 --- /dev/null +++ b/idea/testData/resolve/partialBodyResolve/AnonymousObjects.dump @@ -0,0 +1,2 @@ +Resolve target: value-parameter val p: kotlin.String? +Skipped statements: diff --git a/idea/testData/resolve/partialBodyResolve/AnonymousObjects.kt b/idea/testData/resolve/partialBodyResolve/AnonymousObjects.kt new file mode 100644 index 00000000000..e8c56634b23 --- /dev/null +++ b/idea/testData/resolve/partialBodyResolve/AnonymousObjects.kt @@ -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) + } + } + + p?.size +} \ No newline at end of file diff --git a/idea/testData/resolve/partialBodyResolve/LocalClass.dump b/idea/testData/resolve/partialBodyResolve/LocalClass.dump new file mode 100644 index 00000000000..8671dde7711 --- /dev/null +++ b/idea/testData/resolve/partialBodyResolve/LocalClass.dump @@ -0,0 +1,2 @@ +Resolve target: value-parameter val p: kotlin.String? +Skipped statements: diff --git a/idea/testData/resolve/partialBodyResolve/LocalClass.kt b/idea/testData/resolve/partialBodyResolve/LocalClass.kt new file mode 100644 index 00000000000..ec1cda1ad6e --- /dev/null +++ b/idea/testData/resolve/partialBodyResolve/LocalClass.kt @@ -0,0 +1,11 @@ +fun foo(p: String?) { + class LocalClass { + fun f(): String? { + if (p == null) return null + print(p.size) + return "" + } + } + + p?.size +} \ No newline at end of file diff --git a/idea/testData/resolve/partialBodyResolve/LocalFun.dump b/idea/testData/resolve/partialBodyResolve/LocalFun.dump new file mode 100644 index 00000000000..f938531de0f --- /dev/null +++ b/idea/testData/resolve/partialBodyResolve/LocalFun.dump @@ -0,0 +1,5 @@ +Resolve target: value-parameter val p: kotlin.String? +Skipped statements: +if (p == null) return null +print(p.size) +return "" diff --git a/idea/testData/resolve/partialBodyResolve/LocalFun.kt b/idea/testData/resolve/partialBodyResolve/LocalFun.kt new file mode 100644 index 00000000000..3a15722dffe --- /dev/null +++ b/idea/testData/resolve/partialBodyResolve/LocalFun.kt @@ -0,0 +1,9 @@ +fun foo(p: String?) { + fun local(): String? { + if (p == null) return null + print(p.size) + return "" + } + + p?.size +} \ No newline at end of file diff --git a/idea/testData/resolve/partialBodyResolve/LocalNothingFun.dump b/idea/testData/resolve/partialBodyResolve/LocalNothingFun.dump new file mode 100644 index 00000000000..2edd08e7601 --- /dev/null +++ b/idea/testData/resolve/partialBodyResolve/LocalNothingFun.dump @@ -0,0 +1,2 @@ +Resolve target: value-parameter val p: kotlin.String? smart-casted to kotlin.String +Skipped statements: diff --git a/idea/testData/resolve/partialBodyResolve/LocalNothingFun.kt b/idea/testData/resolve/partialBodyResolve/LocalNothingFun.kt new file mode 100644 index 00000000000..60e8726ac37 --- /dev/null +++ b/idea/testData/resolve/partialBodyResolve/LocalNothingFun.kt @@ -0,0 +1,10 @@ +fun foo(p: String?, p1: Any?) { + if (p1 == null) return + + fun localError(): Nothing = throw Exception() + + if (p == null) { + localError() + } + p.size +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/resolve/PartialBodyResolveTestGenerated.java b/idea/tests/org/jetbrains/jet/resolve/PartialBodyResolveTestGenerated.java index ee359bd6f2d..cf5d98eb54f 100644 --- a/idea/tests/org/jetbrains/jet/resolve/PartialBodyResolveTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/resolve/PartialBodyResolveTestGenerated.java @@ -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");