Trouble getting exception type from kotlin throw statement

Hello, I have trouble getting an exact class of exception from kotlin KtThrowExpression.

For example test data:

class ThrowRuntimeException {
fun throws() {
<caret>throw RuntimeException("")
}
}

From this, what I expect to extract is java.lang.RuntimeException with this test code:

class ExtractExceptionTest : LightCodeInsightFixtureTestCase() {

override fun getTestDataPath(): String = "tests"

fun testExtractRuntimeException() {
myFixture.configureByFile("ThrowRuntimeException.kt")
val editor = myFixture.editor
val psiFile = myFixture.file
val offset = editor.caretModel.offset
val element = psiFile.findElementAt(offset)?.parent as KtThrowExpression
val thrownExpression = element.thrownExpression as KtCallExpression
val nameExpression = thrownExpression.calleeExpression as KtNameReferenceExpression
val descriptor = nameExpression.resolveToCall()?.resultingDescriptor
val declarationDescriptor = descriptor?.containingDeclaration
val exceptionName = DescriptorUtils.getFqName(declarationDescriptor!!).asString()
Assert.assertEquals("java.lang.RuntimeException", exceptionName)
}
}

fun KtElement.resolveToCall(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL): ResolvedCall<out CallableDescriptor>? =
getResolvedCall(analyze(bodyResolveMode))

@JvmOverloads
fun KtElement.analyze(bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL): BindingContext =
getResolutionFacade().analyze(this, bodyResolveMode)

The part that should extract exception is borrowed from kotlin source:

https://github.com/JetBrains/kotlin/blob/e329af093277f2d81a7ecbaa55ad451a0ededa01/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/IfThenUtils.kt#L82

But in this part 

val descriptor = nameExpression.resolveToCall()?.resultingDescriptor

I'm getting a null instead of a resolved descriptor, and do not understand, what is going wrong here

full code with gradle set up: https://www.dropbox.com/s/wb5enebocbebj3z/kotlin-exceptions.zip?dl=0 

1
2 comments

Hello,

The test failure caused by invalid configuration of the dummy project. `LightCodeInsightFixtureTestCase.getProjectDescriptor()` tries to create a project with a mock JDK which is absent in IDEA distribution fetched by org.jetbrains.intellij.gralde plugin.(https://youtrack.jetbrains.com/issue/IJSDK-321)

Here is the possible fix (not very perfomant though, as full JDK is big) :

package some

import com.intellij.openapi.module.Module
import com.intellij.openapi.projectRoots.JavaSdk
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.projectRoots.impl.JavaSdkImpl
import com.intellij.openapi.roots.ContentEntry
import com.intellij.openapi.roots.LanguageLevelModuleExtension
import com.intellij.openapi.roots.ModifiableRootModel
import com.intellij.pom.java.LanguageLevel
import com.intellij.testFramework.LightProjectDescriptor
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
import org.junit.Assert

class ExtractExceptionTest : LightCodeInsightFixtureTestCase() {

override fun getTestDataPath(): String = "tests"

fun testExtractRuntimeException() {
myFixture.configureByText(
"Test.kt",
"""
class ThrowRuntimeException {
fun throws() {
throw <caret>RuntimeException("")
}
}
""".trimIndent()
)
val editor = myFixture.editor
val psiFile = myFixture.file
val offset = editor.caretModel.offset

val element = psiFile.findElementAt(offset)!!
val ktElement = element.parents.firstIsInstance<KtElement>()

val constructorDescriptor = ktElement.resolveMainReferenceToDescriptors().single()
val declarationDescriptor = constructorDescriptor.containingDeclaration!!

val exceptionName = DescriptorUtils.getFqName(declarationDescriptor).asString()
Assert.assertEquals("java.lang.RuntimeException", exceptionName)
}

override fun getProjectDescriptor() = ProjectDescriptorWithFullJDK
}


object ProjectDescriptorWithFullJDK : LightProjectDescriptor() {
override fun getSdk(): Sdk? {
return (JavaSdk.getInstance() as JavaSdkImpl).createJdk(
"JavaHomeJDK",
System.getenv()["JDK_18"]!!, // Path to JDK on local machine.
false
)
}

public override fun configureModule(module: Module, model: ModifiableRootModel, contentEntry: ContentEntry) {
model.getModuleExtension(LanguageLevelModuleExtension::class.java).languageLevel = LanguageLevel.JDK_1_8
}
}

 

0
Avatar
Permanently deleted user

Many thanks, now it working correctly

0

Please sign in to leave a comment.