diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/CodeFragmentAnalyzer.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/CodeFragmentAnalyzer.kt index 1930cec313d..fc3b05569c0 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/CodeFragmentAnalyzer.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/CodeFragmentAnalyzer.kt @@ -70,8 +70,13 @@ public class CodeFragmentAnalyzer( is JetDeclarationWithBody -> this.getBodyExpression() is JetBlockExpression -> this.getStatements().lastOrNull() else -> { - this.siblings(forward = false, withItself = false).firstIsInstanceOrNull() - ?: this.parents.firstIsInstanceOrNull() + val previousSibling = this.siblings(forward = false, withItself = false).firstIsInstanceOrNull() + if (previousSibling != null) return previousSibling + for (parent in this.parents) { + if (parent is JetWhenEntry || parent is JetIfExpression || parent is JetBlockExpression) return this + if (parent is JetExpression) return parent + } + null } } ?: this } diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/CodeInsightUtils.java b/idea/src/org/jetbrains/kotlin/idea/codeInsight/CodeInsightUtils.java index c3cf71ecd15..6754ca54599 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/CodeInsightUtils.java +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/CodeInsightUtils.java @@ -284,4 +284,25 @@ public class CodeInsightUtils { return element; } + + @Nullable + public static T getTopmostElementAtOffset(@NotNull PsiElement element, int offset, @NotNull Class klass) { + T lastElementOfType = null; + if (klass.isInstance(element)) { + lastElementOfType = (T) element; + } + do { + PsiElement parent = element.getParent(); + if (parent == null || (parent.getTextOffset() < offset) || parent instanceof JetBlockExpression) { + break; + } + if (klass.isInstance(parent)) { + lastElementOfType = (T) parent; + } + element = parent; + } + while(true); + + return lastElementOfType; + } } diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinCodeFragmentFactory.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinCodeFragmentFactory.kt index 742a90352da..9468083efaf 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinCodeFragmentFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinCodeFragmentFactory.kt @@ -37,14 +37,17 @@ import com.sun.jdi.PrimitiveValue import com.sun.jdi.Value import org.jetbrains.kotlin.asJava.KotlinLightClass import org.jetbrains.kotlin.idea.JetFileType +import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils import org.jetbrains.kotlin.idea.core.refactoring.j2kText import org.jetbrains.kotlin.idea.debugger.KotlinEditorTextProvider import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext import org.jetbrains.kotlin.types.JetType +import org.jetbrains.kotlin.utils.addToStdlib.check import java.util.HashMap import java.util.concurrent.atomic.AtomicReference +import kotlin.reflect.jvm.java class KotlinCodeFragmentFactory: CodeFragmentFactory() { private val LOG = Logger.getInstance(this.javaClass) @@ -143,14 +146,21 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() { val containingFile = elementAt.containingFile if (containingFile !is JetFile) return null - val expressionAtOffset = PsiTreeUtil.findElementOfClassAtOffset(containingFile, elementAt.textOffset, javaClass(), false) - if (expressionAtOffset != null && KotlinEditorTextProvider.isAcceptedAsCodeFragmentContext(elementAt)) { - return expressionAtOffset + var result = PsiTreeUtil.findElementOfClassAtOffset(containingFile, elementAt.textOffset, javaClass(), false) + if (result.check()) { + return CodeInsightUtils.getTopmostElementAtOffset(result!!, result.textOffset, JetExpression::class.java) } - return KotlinEditorTextProvider.findExpressionInner(elementAt, true) ?: containingFile + result = KotlinEditorTextProvider.findExpressionInner(elementAt, true) + if (result.check()) { + return result + } + + return containingFile } + private fun JetElement?.check(): Boolean = this != null && this.check { KotlinEditorTextProvider.isAcceptedAsCodeFragmentContext(it) } != null + //internal for tests fun createCodeFragmentForLabeledObjects(project: Project, markupMap: Map<*, ValueMarkup>): Pair> { val sb = StringBuilder() diff --git a/idea/testData/checker/codeFragments/smartCasts.kt b/idea/testData/checker/codeFragments/smartCasts.kt index c8f7f84b6ab..7125b481a85 100644 --- a/idea/testData/checker/codeFragments/smartCasts.kt +++ b/idea/testData/checker/codeFragments/smartCasts.kt @@ -1,6 +1,6 @@ fun foo() { val a: Int? = 1 if (a != null) { - a + a } } \ No newline at end of file