Add debug information on any of ResolutionFacade API failures
This commit is contained in:
+3
-3
@@ -419,16 +419,16 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
|
|||||||
val scripts = specialFiles.filterScripts()
|
val scripts = specialFiles.filterScripts()
|
||||||
if (scripts.isNotEmpty()) {
|
if (scripts.isNotEmpty()) {
|
||||||
val projectFacade = getFacadeForScripts(scripts)
|
val projectFacade = getFacadeForScripts(scripts)
|
||||||
return ModuleResolutionFacadeImpl(projectFacade, moduleInfo)
|
return ModuleResolutionFacadeImpl(projectFacade, moduleInfo).createdFor(scripts, moduleInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (specialFiles.isNotEmpty()) {
|
if (specialFiles.isNotEmpty()) {
|
||||||
val projectFacade = getFacadeForSpecialFiles(specialFiles)
|
val projectFacade = getFacadeForSpecialFiles(specialFiles)
|
||||||
return ModuleResolutionFacadeImpl(projectFacade, moduleInfo)
|
return ModuleResolutionFacadeImpl(projectFacade, moduleInfo).createdFor(specialFiles, moduleInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
val platform = TargetPlatformDetector.getPlatform(file)
|
val platform = TargetPlatformDetector.getPlatform(file)
|
||||||
return getResolutionFacadeByModuleInfo(moduleInfo, platform)
|
return getResolutionFacadeByModuleInfo(moduleInfo, platform).createdFor(emptyList(), moduleInfo, platform)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getResolutionFacadeByFile(file: PsiFile, platform: TargetPlatform): ResolutionFacade? {
|
override fun getResolutionFacadeByFile(file: PsiFile, platform: TargetPlatform): ResolutionFacade? {
|
||||||
|
|||||||
+205
@@ -0,0 +1,205 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.caches.resolve
|
||||||
|
|
||||||
|
import com.intellij.openapi.diagnostic.ControlFlowException
|
||||||
|
import com.intellij.openapi.module.ModuleUtil
|
||||||
|
import com.intellij.openapi.project.IndexNotReadyException
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiFile
|
||||||
|
import com.intellij.psi.PsiNamedElement
|
||||||
|
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||||
|
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
|
||||||
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.TargetPlatform
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments
|
||||||
|
|
||||||
|
private class ResolutionFacadeWithDebugInfo(
|
||||||
|
private val delegate: ResolutionFacade,
|
||||||
|
private val creationPlace: CreationPlace
|
||||||
|
) : ResolutionFacade {
|
||||||
|
override val project: Project
|
||||||
|
get() = delegate.project
|
||||||
|
|
||||||
|
override fun analyze(element: KtElement, bodyResolveMode: BodyResolveMode): BindingContext {
|
||||||
|
return wrapExceptions({ ResolvingWhat(listOf(element), bodyResolveMode) }) {
|
||||||
|
delegate.analyze(element, bodyResolveMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun analyze(elements: Collection<KtElement>, bodyResolveMode: BodyResolveMode): BindingContext {
|
||||||
|
return wrapExceptions({ ResolvingWhat(elements, bodyResolveMode) }) {
|
||||||
|
delegate.analyze(elements, bodyResolveMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun analyzeWithAllCompilerChecks(elements: Collection<KtElement>): AnalysisResult {
|
||||||
|
return wrapExceptions({ ResolvingWhat(elements) }) {
|
||||||
|
delegate.analyzeWithAllCompilerChecks(elements)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resolveToDescriptor(declaration: KtDeclaration, bodyResolveMode: BodyResolveMode): DeclarationDescriptor {
|
||||||
|
return wrapExceptions({ ResolvingWhat(listOf(declaration), bodyResolveMode) }) {
|
||||||
|
delegate.resolveToDescriptor(declaration, bodyResolveMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val moduleDescriptor: ModuleDescriptor
|
||||||
|
get() = delegate.moduleDescriptor
|
||||||
|
|
||||||
|
override fun <T : Any> getFrontendService(serviceClass: Class<T>): T {
|
||||||
|
return wrapExceptions({ ResolvingWhat(serviceClass = serviceClass) }) {
|
||||||
|
delegate.getFrontendService(serviceClass)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : Any> getIdeService(serviceClass: Class<T>): T {
|
||||||
|
return wrapExceptions({ ResolvingWhat(serviceClass = serviceClass) }) {
|
||||||
|
delegate.getIdeService(serviceClass)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : Any> getFrontendService(element: PsiElement, serviceClass: Class<T>): T {
|
||||||
|
return wrapExceptions({ ResolvingWhat(listOf(element), serviceClass = serviceClass) }) {
|
||||||
|
delegate.getFrontendService(element, serviceClass)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : Any> tryGetFrontendService(element: PsiElement, serviceClass: Class<T>): T? {
|
||||||
|
return wrapExceptions({ ResolvingWhat(listOf(element), serviceClass = serviceClass) }) {
|
||||||
|
delegate.tryGetFrontendService(element, serviceClass)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : Any> getFrontendService(moduleDescriptor: ModuleDescriptor, serviceClass: Class<T>): T {
|
||||||
|
return wrapExceptions({ ResolvingWhat(serviceClass = serviceClass, moduleDescriptor = moduleDescriptor) }) {
|
||||||
|
delegate.getFrontendService(moduleDescriptor, serviceClass)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun <R> wrapExceptions(resolvingWhat: () -> ResolvingWhat, body: () -> R): R {
|
||||||
|
try {
|
||||||
|
return body()
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
if (e is ControlFlowException) {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
throw KotlinIdeaResolutionException(e, resolvingWhat(), creationPlace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class KotlinIdeaResolutionException(
|
||||||
|
cause: Throwable,
|
||||||
|
resolvingWhat: ResolvingWhat,
|
||||||
|
creationPlace: CreationPlace
|
||||||
|
) : KotlinExceptionWithAttachments("Kotlin resolution encountered a problem while ${resolvingWhat.shortDescription()}", cause) {
|
||||||
|
init {
|
||||||
|
withAttachment("info.txt", buildString {
|
||||||
|
append(resolvingWhat.description())
|
||||||
|
appendln("---------------------------------------------")
|
||||||
|
append(creationPlace.description())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class CreationPlace(
|
||||||
|
private val elements: Collection<KtElement>,
|
||||||
|
private val moduleInfo: ModuleInfo?,
|
||||||
|
private val platform: TargetPlatform?
|
||||||
|
) {
|
||||||
|
fun description() = buildString {
|
||||||
|
appendln("Resolver created for:")
|
||||||
|
for (element in elements) {
|
||||||
|
appendElement(element)
|
||||||
|
}
|
||||||
|
if (moduleInfo != null) {
|
||||||
|
appendln("Provided module info: $moduleInfo")
|
||||||
|
}
|
||||||
|
if (platform != null) {
|
||||||
|
appendln("Provided platform: $platform")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ResolvingWhat(
|
||||||
|
private val elements: Collection<PsiElement> = emptyList(),
|
||||||
|
private val bodyResolveMode: BodyResolveMode? = null,
|
||||||
|
private val serviceClass: Class<*>? = null,
|
||||||
|
private val moduleDescriptor: ModuleDescriptor? = null
|
||||||
|
) {
|
||||||
|
fun shortDescription() = serviceClass?.let { "getting service ${serviceClass.simpleName}" }
|
||||||
|
?: "analyzing ${elements.firstOrNull()?.javaClass?.simpleName ?: ""}"
|
||||||
|
|
||||||
|
fun description(): String {
|
||||||
|
return buildString {
|
||||||
|
appendln("Failed performing task:")
|
||||||
|
if (serviceClass != null) {
|
||||||
|
appendln("Getting service: ${serviceClass.name}")
|
||||||
|
} else {
|
||||||
|
append("Analyzing code")
|
||||||
|
if (bodyResolveMode != null) {
|
||||||
|
append(" in BodyResolveMode.$bodyResolveMode")
|
||||||
|
}
|
||||||
|
appendln()
|
||||||
|
}
|
||||||
|
appendln("Elements:")
|
||||||
|
for (element in elements) {
|
||||||
|
appendElement(element)
|
||||||
|
}
|
||||||
|
if (moduleDescriptor != null) {
|
||||||
|
appendln("Provided module descriptor for module ${moduleDescriptor.getCapability(ModuleInfo.Capability)}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun StringBuilder.appendElement(element: PsiElement) {
|
||||||
|
fun info(key: String, value: String?) {
|
||||||
|
appendln(" $key = $value")
|
||||||
|
}
|
||||||
|
|
||||||
|
appendln("Element of type: ${element.javaClass.simpleName}:")
|
||||||
|
if (element is PsiNamedElement) {
|
||||||
|
info("name", element.name)
|
||||||
|
}
|
||||||
|
info("isValid", element.isValid.toString())
|
||||||
|
info("isPhysical", element.isPhysical.toString())
|
||||||
|
if (element is PsiFile) {
|
||||||
|
info("containingFile.name", element.containingFile.name)
|
||||||
|
}
|
||||||
|
val moduleInfo = ifIndexReady { element.getModuleInfo() }
|
||||||
|
info("moduleInfo", moduleInfo?.toString() ?: "<index not ready>")
|
||||||
|
if (moduleInfo != null) {
|
||||||
|
info("moduleInfo.platform", moduleInfo.platform?.toString())
|
||||||
|
}
|
||||||
|
info("ideaModule", ifIndexReady { ModuleUtil.findModuleForFile(element.containingFile)?.name ?: "null" } ?: "<index not ready>")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T : Any> ifIndexReady(body: () -> T): T? = try {
|
||||||
|
body()
|
||||||
|
} catch (e: IndexNotReadyException) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun ResolutionFacade.createdFor(
|
||||||
|
files: Collection<KtFile>,
|
||||||
|
moduleInfo: ModuleInfo?,
|
||||||
|
platform: TargetPlatform? = null
|
||||||
|
): ResolutionFacade {
|
||||||
|
return ResolutionFacadeWithDebugInfo(this, CreationPlace(files, moduleInfo, platform))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user