[Analysis API] do not throw exception when KtCall is improperly resolved

Log the exception instead. This way the analysis of the file will not be stuck after finding an improperly resolved call
This commit is contained in:
Ilya Kirillov
2023-02-02 14:59:46 +01:00
committed by Space Team
parent 4a872928dd
commit 8b286577c7
3 changed files with 42 additions and 8 deletions
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.analysis.api.fir.components package org.jetbrains.kotlin.analysis.api.fir.components
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.calls.* import org.jetbrains.kotlin.analysis.api.calls.*
import org.jetbrains.kotlin.analysis.api.diagnostics.KtDiagnostic import org.jetbrains.kotlin.analysis.api.diagnostics.KtDiagnostic
import org.jetbrains.kotlin.analysis.api.diagnostics.KtNonBoundToPsiErrorDiagnostic import org.jetbrains.kotlin.analysis.api.diagnostics.KtNonBoundToPsiErrorDiagnostic
@@ -29,6 +30,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolver.AllCandidatesResolver import org.jetbrains.kotlin.analysis.low.level.api.fir.resolver.AllCandidatesResolver
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirEntry import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirEntry
import org.jetbrains.kotlin.analysis.utils.errors.ExceptionAttachmentBuilder
import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment
import org.jetbrains.kotlin.analysis.utils.errors.withPsiEntry import org.jetbrains.kotlin.analysis.utils.errors.withPsiEntry
import org.jetbrains.kotlin.analysis.utils.errors.rethrowExceptionWithDetails import org.jetbrains.kotlin.analysis.utils.errors.rethrowExceptionWithDetails
@@ -1275,11 +1277,9 @@ internal class KtFirCallResolver(
} }
} }
override fun unresolvedKtCallError(psi: KtElement): Nothing { @KtAnalysisApiInternals
buildErrorWithAttachment("${psi::class.simpleName}(${psi::class.simpleName}) should always resolve to a KtCallInfo") { override fun provideAdditionalAttachmentToUnresolvedCall(psi: KtElement, builder: ExceptionAttachmentBuilder) {
withPsiEntry("psi", psi) psi.getOrBuildFir(firResolveSession)?.let { builder.withFirEntry("fir", it) }
psi.getOrBuildFir(firResolveSession)?.let { withFirEntry("fir", it) }
}
} }
private inline fun <R> wrapError(element: KtElement, action: () -> R): R { private inline fun <R> wrapError(element: KtElement, action: () -> R): R {
@@ -5,10 +5,15 @@
package org.jetbrains.kotlin.analysis.api.components package org.jetbrains.kotlin.analysis.api.components
import com.intellij.openapi.diagnostic.Logger
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.calls.KtCallCandidateInfo import org.jetbrains.kotlin.analysis.api.calls.KtCallCandidateInfo
import org.jetbrains.kotlin.analysis.api.calls.KtCallInfo import org.jetbrains.kotlin.analysis.api.calls.KtCallInfo
import org.jetbrains.kotlin.analysis.api.calls.KtErrorCallInfo
import org.jetbrains.kotlin.analysis.api.diagnostics.KtNonBoundToPsiErrorDiagnostic
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment import org.jetbrains.kotlin.analysis.utils.errors.ExceptionAttachmentBuilder
import org.jetbrains.kotlin.analysis.utils.errors.logErrorWithAttachment
import org.jetbrains.kotlin.analysis.utils.errors.withPsiEntry import org.jetbrains.kotlin.analysis.utils.errors.withPsiEntry
import org.jetbrains.kotlin.psi.KtArrayAccessExpression import org.jetbrains.kotlin.psi.KtArrayAccessExpression
import org.jetbrains.kotlin.psi.KtCallElement import org.jetbrains.kotlin.psi.KtCallElement
@@ -20,13 +25,30 @@ public abstract class KtCallResolver : KtAnalysisSessionComponent() {
public abstract fun collectCallCandidates(psi: KtElement): List<KtCallCandidateInfo> public abstract fun collectCallCandidates(psi: KtElement): List<KtCallCandidateInfo>
public open fun unresolvedKtCallError(psi: KtElement): Nothing { @KtAnalysisApiInternals
buildErrorWithAttachment("${psi::class.simpleName}(${psi::class.simpleName}) should always resolve to a KtCallInfo") { public fun unresolvedKtCallError(psi: KtElement): KtErrorCallInfo {
LOG.logErrorWithAttachment("${psi::class.simpleName} should always resolve to a KtCallInfo") {
withPsiEntry("psi", psi) withPsiEntry("psi", psi)
provideAdditionalAttachmentToUnresolvedCall(psi, this)
} }
return KtErrorCallInfo(
_candidateCalls = emptyList(),
KtNonBoundToPsiErrorDiagnostic(factoryName = null, "Unresolved call", token),
token
)
}
@KtAnalysisApiInternals
protected open fun provideAdditionalAttachmentToUnresolvedCall(psi: KtElement, builder: ExceptionAttachmentBuilder) {
}
public companion object {
@KtAnalysisApiInternals
public val LOG: Logger = Logger.getInstance(KtCallResolver::class.java)
} }
} }
@OptIn(KtAnalysisApiInternals::class)
public interface KtCallResolverMixIn : KtAnalysisSessionMixIn { public interface KtCallResolverMixIn : KtAnalysisSessionMixIn {
public fun KtElement.resolveCall(): KtCallInfo? = public fun KtElement.resolveCall(): KtCallInfo? =
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.analysis.utils.errors package org.jetbrains.kotlin.analysis.utils.errors
import com.intellij.openapi.diagnostic.Attachment
import com.intellij.openapi.diagnostic.Logger
import org.jetbrains.kotlin.analysis.utils.printer.PrettyPrinter import org.jetbrains.kotlin.analysis.utils.printer.PrettyPrinter
import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint
import org.jetbrains.kotlin.util.SourceCodeAnalysisException import org.jetbrains.kotlin.util.SourceCodeAnalysisException
@@ -70,6 +72,16 @@ public inline fun buildErrorWithAttachment(
throw exception throw exception
} }
public inline fun Logger.logErrorWithAttachment(
message: String,
cause: Exception? = null,
attachmentName: String = "info.txt",
buildAttachment: ExceptionAttachmentBuilder.() -> Unit = {}
) {
val attachment = Attachment(attachmentName, ExceptionAttachmentBuilder().apply(buildAttachment).buildString())
this.error(message, cause, attachment)
}
public inline fun rethrowExceptionWithDetails( public inline fun rethrowExceptionWithDetails(
message: String, message: String,
exception: Exception, exception: Exception,