diff --git a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalysisResult.kt b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalysisResult.kt index 73717ca991f..e8c7a5001f4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalysisResult.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalysisResult.kt @@ -52,9 +52,9 @@ open class AnalysisResult protected constructor( fun isError(): Boolean = this is InternalError || this is CompilationError fun throwIfError() { - when { - this is InternalError -> throw IllegalStateException("failed to analyze: " + error, error) - this is CompilationError -> throw CompilationErrorException() + when (this) { + is InternalError -> throw IllegalStateException("failed to analyze: $error", error) + is CompilationError -> throw CompilationErrorException() } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/DiagnosticSink.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/DiagnosticSink.java index 37d6a6fbb14..30043b68da1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/DiagnosticSink.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/DiagnosticSink.java @@ -53,6 +53,15 @@ public interface DiagnosticSink { } }; + interface DiagnosticsCallback { + void callback(Diagnostic diagnostic); + } + void report(@NotNull Diagnostic diagnostic); + + default void setCallback(@NotNull DiagnosticsCallback callback) { } + + default void resetCallback() { } + boolean wantsDiagnostics(); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/RenderingContext.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/RenderingContext.kt index ff7304fa24d..aa726637803 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/RenderingContext.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/RenderingContext.kt @@ -48,16 +48,16 @@ sealed class RenderingContext { } @JvmStatic - fun fromDiagnostic(d: Diagnostic): RenderingContext { - val parameters = when (d) { - is SimpleDiagnostic<*> -> listOf() - is DiagnosticWithParameters1<*, *> -> listOf(d.a) - is DiagnosticWithParameters2<*, *, *> -> listOf(d.a, d.b) - is DiagnosticWithParameters3<*, *, *, *> -> listOf(d.a, d.b, d.c) - is ParametrizedDiagnostic<*> -> error("Unexpected diagnostic: ${d::class.java}") - else -> listOf() - } - return Impl(parameters) + fun parameters(d: Diagnostic): List = when (d) { + is SimpleDiagnostic<*> -> listOf() + is DiagnosticWithParameters1<*, *> -> listOf(d.a) + is DiagnosticWithParameters2<*, *, *> -> listOf(d.a, d.b) + is DiagnosticWithParameters3<*, *, *, *> -> listOf(d.a, d.b, d.c) + is ParametrizedDiagnostic<*> -> error("Unexpected diagnostic: ${d::class.java}") + else -> listOf() } + + @JvmStatic + fun fromDiagnostic(d: Diagnostic): RenderingContext = Impl(parameters(d)) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AbstractFilteringTrace.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AbstractFilteringTrace.kt index 3ef6e842a1f..e98c6e2c2fd 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AbstractFilteringTrace.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AbstractFilteringTrace.kt @@ -37,6 +37,8 @@ abstract class AbstractFilteringTrace( } override fun report(diagnostic: Diagnostic) { + diagnosticsCallback?.callback(diagnostic) + parentTrace.report(diagnostic) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatingBindingTrace.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatingBindingTrace.kt index 59c1c93dc27..b54b1cba8e3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatingBindingTrace.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatingBindingTrace.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve import com.google.common.collect.ImmutableMap import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.resolve.diagnostics.BindingContextSuppressCache import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics @@ -156,6 +157,18 @@ open class DelegatingBindingTrace( mutableDiagnostics.report(diagnostic) } + protected var diagnosticsCallback: DiagnosticSink.DiagnosticsCallback? = null + + override fun setCallback(callback: DiagnosticSink.DiagnosticsCallback) { + diagnosticsCallback = callback + mutableDiagnostics?.setCallback(callback) + } + + override fun resetCallback() { + diagnosticsCallback = null + mutableDiagnostics?.resetCallback() + } + override fun wantsDiagnostics(): Boolean = mutableDiagnostics != null override fun toString(): String = name diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/Diagnostics.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/Diagnostics.kt index 80e4c0f0c03..04231909f5a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/Diagnostics.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/Diagnostics.kt @@ -16,9 +16,10 @@ package org.jetbrains.kotlin.resolve.diagnostics -import com.intellij.psi.PsiElement import com.intellij.openapi.util.ModificationTracker +import com.intellij.psi.PsiElement import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.DiagnosticSink.DiagnosticsCallback import org.jetbrains.kotlin.diagnostics.GenericDiagnostics interface Diagnostics : GenericDiagnostics { @@ -37,6 +38,9 @@ interface Diagnostics : GenericDiagnostics { fun noSuppression(): Diagnostics + fun setCallback(callback: DiagnosticsCallback) {} + fun resetCallback() {} + companion object { val EMPTY: Diagnostics = object : Diagnostics { override fun noSuppression(): Diagnostics = this diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/DiagnosticsWithSuppression.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/DiagnosticsWithSuppression.java index 4463565bd84..f759209c551 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/DiagnosticsWithSuppression.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/DiagnosticsWithSuppression.java @@ -23,6 +23,7 @@ import kotlin.collections.CollectionsKt; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.TestOnly; import org.jetbrains.kotlin.diagnostics.Diagnostic; +import org.jetbrains.kotlin.diagnostics.DiagnosticSink; import java.util.Collection; import java.util.Iterator; @@ -73,6 +74,16 @@ public class DiagnosticsWithSuppression implements Diagnostics { throw new IllegalStateException("Trying to obtain modification tracker for readonly DiagnosticsWithSuppression."); } + @Override + public void setCallback(@NotNull DiagnosticSink.DiagnosticsCallback callback) { + + } + + @Override + public void resetCallback() { + + } + @TestOnly @NotNull public Collection getDiagnostics() { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/KotlinSuppressCache.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/KotlinSuppressCache.kt index d870fc079c3..259de46c32a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/KotlinSuppressCache.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/KotlinSuppressCache.kt @@ -24,10 +24,7 @@ import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Severity -import org.jetbrains.kotlin.psi.KtAnnotated -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.KtStubbedPsiUtil -import org.jetbrains.kotlin.psi.doNotAnalyze +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.constants.ArrayValue import org.jetbrains.kotlin.resolve.constants.StringValue @@ -111,7 +108,12 @@ abstract class KotlinSuppressCache { This way we need no more lookups than the number of suppress() annotations from here to the root. */ - private fun isSuppressedByAnnotated(suppressionKey: String, severity: Severity, annotated: KtAnnotated, debugDepth: Int): Boolean { + private fun isSuppressedByAnnotated( + suppressionKey: String, + severity: Severity, + annotated: KtAnnotated, + debugDepth: Int + ): Boolean { val suppressor = getOrCreateSuppressor(annotated) if (suppressor.isSuppressed(suppressionKey, severity)) return true @@ -140,6 +142,7 @@ abstract class KotlinSuppressCache { private fun getSuppressingStrings(annotated: KtAnnotated): Set { val builder = ImmutableSet.builder() + for (annotationDescriptor in getSuppressionAnnotations(annotated)) { processAnnotation(builder, annotationDescriptor) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/MutableDiagnosticsWithSuppression.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/MutableDiagnosticsWithSuppression.kt index 7157dfdec02..ddbf703cce7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/MutableDiagnosticsWithSuppression.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/MutableDiagnosticsWithSuppression.kt @@ -22,12 +22,16 @@ import com.intellij.psi.util.CachedValueProvider import com.intellij.util.CachedValueImpl import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.DiagnosticSink +import org.jetbrains.kotlin.psi.KtAnnotationEntry +import org.jetbrains.kotlin.psi.KtStubbedPsiUtil class MutableDiagnosticsWithSuppression( private val suppressCache: KotlinSuppressCache, private val delegateDiagnostics: Diagnostics, ) : Diagnostics { private val diagnosticList = ArrayList() + private var diagnosticsCallback: DiagnosticSink.DiagnosticsCallback? = null //NOTE: CachedValuesManager is not used because it requires Project passed to this object private val cache = CachedValueImpl { @@ -43,16 +47,38 @@ class MutableDiagnosticsWithSuppression( override fun forElement(psiElement: PsiElement) = readonlyView().forElement(psiElement) override fun noSuppression() = readonlyView().noSuppression() + override fun setCallback(callback: DiagnosticSink.DiagnosticsCallback) { + assert(diagnosticsCallback == null) { "diagnostic callback has been already registered" } + diagnosticsCallback = callback + delegateDiagnostics.setCallback(callback) + } + + override fun resetCallback() { + diagnosticsCallback = null + delegateDiagnostics.resetCallback() + } + //essential that this list is readonly fun getOwnDiagnostics(): List { return diagnosticList } fun report(diagnostic: Diagnostic) { + onFlyDiagnosticsCallback(diagnostic)?.callback(diagnostic) + diagnosticList.add(diagnostic) modificationTracker.incModificationCount() } + private fun onFlyDiagnosticsCallback(diagnostic: Diagnostic): DiagnosticSink.DiagnosticsCallback? = + diagnosticsCallback.takeIf { + diagnosticsCallback != null && + // Due to a potential recursion in filter.invoke (via LazyAnnotations) do not try to report + // diagnostic on fly if it happened in annotations + KtStubbedPsiUtil.getPsiOrStubParent(diagnostic.psiElement, KtAnnotationEntry::class.java, false) == null && + suppressCache.filter.invoke(diagnostic) + } + fun clear() { diagnosticList.clear() modificationTracker.incModificationCount() diff --git a/compiler/frontend/src/org/jetbrains/kotlin/storage/LockBasedLazyResolveStorageManager.kt b/compiler/frontend/src/org/jetbrains/kotlin/storage/LockBasedLazyResolveStorageManager.kt index cf1aa29901e..e9db0d08abf 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/storage/LockBasedLazyResolveStorageManager.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/storage/LockBasedLazyResolveStorageManager.kt @@ -22,7 +22,6 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice import org.jetbrains.kotlin.util.slicedMap.WritableSlice -import org.jetbrains.kotlin.resolve.TraceEntryFilter import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics import com.intellij.util.containers.ContainerUtil import org.jetbrains.kotlin.psi.KtExpression diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/caches/resolve/resolutionApi.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/caches/resolve/resolutionApi.kt index 5c4e2c629a3..443eacba99e 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/caches/resolve/resolutionApi.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/caches/resolve/resolutionApi.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.idea.FrontendInternals +import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.* @@ -167,8 +168,11 @@ inline fun T.analyzeWithContent(): BindingContext where T : KtDeclar * @ref [org.jetbrains.kotlin.idea.caches.resolve.PerFileAnalysisCache] */ fun KtFile.analyzeWithAllCompilerChecks(vararg extraFiles: KtFile): AnalysisResult = + this.analyzeWithAllCompilerChecks(null, *extraFiles) + +fun KtFile.analyzeWithAllCompilerChecks(callback: ((Diagnostic) -> Unit)?, vararg extraFiles: KtFile): AnalysisResult = KotlinCacheService.getInstance(project).getResolutionFacade(listOf(this) + extraFiles.toList()) - .analyzeWithAllCompilerChecks(listOf(this)) + .analyzeWithAllCompilerChecks(listOf(this), callback) /** * This function is expected to produce the same result as compiler for the given element and its children (including diagnostics, diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/resolve/ResolutionFacade.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/resolve/ResolutionFacade.kt index 91b8fb6c346..6124878609c 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/resolve/ResolutionFacade.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/resolve/ResolutionFacade.kt @@ -12,6 +12,8 @@ import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.analyzer.ResolverForProject import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.idea.FrontendInternals import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtElement @@ -24,7 +26,7 @@ interface ResolutionFacade { fun analyze(element: KtElement, bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL): BindingContext fun analyze(elements: Collection, bodyResolveMode: BodyResolveMode): BindingContext - fun analyzeWithAllCompilerChecks(elements: Collection): AnalysisResult + fun analyzeWithAllCompilerChecks(elements: Collection, callback: DiagnosticSink.DiagnosticsCallback? = null): AnalysisResult fun resolveToDescriptor(declaration: KtDeclaration, bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL): DeclarationDescriptor diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ModuleResolutionFacadeImpl.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ModuleResolutionFacadeImpl.kt index ec92de74a0e..39e05c2e189 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ModuleResolutionFacadeImpl.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ModuleResolutionFacadeImpl.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.container.tryGetService import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.idea.FrontendInternals +import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.project.ResolveElementCache import org.jetbrains.kotlin.idea.resolve.ResolutionFacade @@ -75,11 +76,14 @@ internal class ModuleResolutionFacadeImpl( } } - override fun analyzeWithAllCompilerChecks(elements: Collection): AnalysisResult { + override fun analyzeWithAllCompilerChecks( + elements: Collection, + callback: DiagnosticSink.DiagnosticsCallback? + ): AnalysisResult { ResolveInDispatchThreadManager.assertNoResolveInDispatchThread() return runWithCancellationCheck { - projectFacade.getAnalysisResultsForElements(elements) + projectFacade.getAnalysisResultsForElements(elements, callback) } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/PerFileAnalysisCache.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/PerFileAnalysisCache.kt index 91bf8671418..84c206f2acd 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/PerFileAnalysisCache.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/PerFileAnalysisCache.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.context.withModule import org.jetbrains.kotlin.context.withProject import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.diagnostics.DiagnosticUtils import org.jetbrains.kotlin.frontend.di.createContainerForLazyBodyResolve import org.jetbrains.kotlin.idea.caches.project.getModuleInfo @@ -89,32 +90,50 @@ internal class PerFileAnalysisCache(val file: KtFile, componentProvider: Compone return null } - internal fun getAnalysisResults(element: KtElement): AnalysisResult { + internal fun getAnalysisResults(element: KtElement, callback: DiagnosticSink.DiagnosticsCallback? = null): AnalysisResult { check(element) val analyzableParent = KotlinResolveDataProvider.findAnalyzableParent(element) ?: return AnalysisResult.EMPTY + fun handleResult(result: AnalysisResult, callback: DiagnosticSink.DiagnosticsCallback?): AnalysisResult { + callback?.let { result.bindingContext.diagnostics.forEach(it::callback) } + return result + } + return guardLock.guarded { // step 1: perform incremental analysis IF it is applicable - getIncrementalAnalysisResult()?.let { return@guarded it } + getIncrementalAnalysisResult(callback)?.let { + return@guarded handleResult(it, callback) + } // cache does not contain AnalysisResult per each kt/psi element // instead it looks up analysis for its parents - see lookUp(analyzableElement) // step 2: return result if it is cached lookUp(analyzableParent)?.let { - return@guarded it + return@guarded handleResult(it, callback) } + val localDiagnostics = mutableSetOf() + val localCallback = if (callback != null) { d: Diagnostic -> + localDiagnostics.add(d) + callback.callback(d) + } else null + // step 3: perform analyze of analyzableParent as nothing has been cached yet - val result = analyze(analyzableParent) + val result = analyze(analyzableParent, null, localCallback) + + // some of diagnostics could be not handled with a callback - send out the rest + callback?.let { c -> + result.bindingContext.diagnostics.filterNot { it in localDiagnostics }.forEach(c::callback) + } cache[analyzableParent] = result return@guarded result } } - private fun getIncrementalAnalysisResult(): AnalysisResult? { + private fun getIncrementalAnalysisResult(callback: DiagnosticSink.DiagnosticsCallback?): AnalysisResult? { updateFileResultFromCache() val inBlockModifications = file.inBlockModifications @@ -151,7 +170,9 @@ internal class PerFileAnalysisCache(val file: KtFile, componentProvider: Compone ) } - val newResult = analyze(inBlockModification, trace) + callback?.let { trace.parentDiagnosticsApartElement.forEach(it::callback) } + + val newResult = analyze(inBlockModification, trace, callback) analysisResult = wrapResult(result, newResult, trace) } file.clearInBlockModifications() @@ -224,7 +245,11 @@ internal class PerFileAnalysisCache(val file: KtFile, componentProvider: Compone } } - private fun analyze(analyzableElement: KtElement, bindingTrace: BindingTrace? = null): AnalysisResult { + private fun analyze( + analyzableElement: KtElement, + bindingTrace: BindingTrace?, + callback: DiagnosticSink.DiagnosticsCallback? + ): AnalysisResult { ProgressIndicatorProvider.checkCanceled() val project = analyzableElement.project @@ -242,7 +267,8 @@ internal class PerFileAnalysisCache(val file: KtFile, componentProvider: Compone codeFragmentAnalyzer, bodyResolveCache, analyzableElement, - bindingTrace + bindingTrace, + callback ) } catch (e: ProcessCanceledException) { throw e @@ -412,12 +438,14 @@ private object KotlinResolveDataProvider { codeFragmentAnalyzer: CodeFragmentAnalyzer, bodyResolveCache: BodyResolveCache, analyzableElement: KtElement, - bindingTrace: BindingTrace? + bindingTrace: BindingTrace?, + callback: DiagnosticSink.DiagnosticsCallback? ): AnalysisResult { try { if (analyzableElement is KtCodeFragment) { val bodyResolveMode = BodyResolveMode.PARTIAL_FOR_COMPLETION - val bindingContext = codeFragmentAnalyzer.analyzeCodeFragment(analyzableElement, bodyResolveMode).bindingContext + val trace: BindingTrace = codeFragmentAnalyzer.analyzeCodeFragment(analyzableElement, bodyResolveMode) + val bindingContext = trace.bindingContext return AnalysisResult.success(bindingContext, moduleDescriptor) } @@ -427,34 +455,40 @@ private object KotlinResolveDataProvider { allowSliceRewrite = true ) - val moduleInfo = analyzableElement.containingFile.getModuleInfo() + val moduleInfo = analyzableElement.containingKtFile.getModuleInfo() val targetPlatform = moduleInfo.platform - /* - Note that currently we *have* to re-create LazyTopDownAnalyzer with custom trace in order to disallow resolution of - bodies in top-level trace (trace from DI-container). - Resolving bodies in top-level trace may lead to memory leaks and incorrect resolution, because top-level - trace isn't invalidated on in-block modifications (while body resolution surely does) + callback?.let { trace.setCallback(it) } - Also note that for function bodies, we'll create DelegatingBindingTrace in ResolveElementCache anyways - (see 'functionAdditionalResolve'). However, this trace is still needed, because we have other - codepaths for other KtDeclarationWithBodies (like property accessors/secondary constructors/class initializers) - */ - val lazyTopDownAnalyzer = createContainerForLazyBodyResolve( - //TODO: should get ModuleContext - globalContext.withProject(project).withModule(moduleDescriptor), - resolveSession, - trace, - targetPlatform, - bodyResolveCache, - targetPlatform.findAnalyzerServices(project), - analyzableElement.languageVersionSettings, - IdeaModuleStructureOracle(), - IdeMainFunctionDetectorFactory() - ).get() + try { + /* + Note that currently we *have* to re-create LazyTopDownAnalyzer with custom trace in order to disallow resolution of + bodies in top-level trace (trace from DI-container). + Resolving bodies in top-level trace may lead to memory leaks and incorrect resolution, because top-level + trace isn't invalidated on in-block modifications (while body resolution surely does) - lazyTopDownAnalyzer.analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, listOf(analyzableElement)) + Also note that for function bodies, we'll create DelegatingBindingTrace in ResolveElementCache anyways + (see 'functionAdditionalResolve'). However, this trace is still needed, because we have other + codepaths for other KtDeclarationWithBodies (like property accessors/secondary constructors/class initializers) + */ + val lazyTopDownAnalyzer = createContainerForLazyBodyResolve( + //TODO: should get ModuleContext + globalContext.withProject(project).withModule(moduleDescriptor), + resolveSession, + trace, + targetPlatform, + bodyResolveCache, + targetPlatform.findAnalyzerServices(project), + analyzableElement.languageVersionSettings, + IdeaModuleStructureOracle(), + IdeMainFunctionDetectorFactory() + ).get() + + lazyTopDownAnalyzer.analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, listOf(analyzableElement)) + } finally { + trace.resetCallback() + } return AnalysisResult.success(trace.bindingContext, moduleDescriptor) } catch (e: ProcessCanceledException) { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ProjectResolutionFacade.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ProjectResolutionFacade.kt index 14c2100ab61..416bd50016b 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ProjectResolutionFacade.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ProjectResolutionFacade.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.analyzer.* import org.jetbrains.kotlin.context.GlobalContextImpl import org.jetbrains.kotlin.context.withProject import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.idea.caches.project.* import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener @@ -143,10 +144,13 @@ internal class ProjectResolutionFacade( internal fun findModuleDescriptor(ideaModuleInfo: IdeaModuleInfo): ModuleDescriptor { return cachedResolverForProject.descriptorForModule(ideaModuleInfo) } - + internal fun getResolverForProject(): ResolverForProject = cachedResolverForProject - internal fun getAnalysisResultsForElements(elements: Collection): AnalysisResult { + internal fun getAnalysisResultsForElements( + elements: Collection, + callback: DiagnosticSink.DiagnosticsCallback? = null + ): AnalysisResult { assert(elements.isNotEmpty()) { "elements collection should not be empty" } val cache = analysisResultsSimpleLock.guarded { @@ -157,7 +161,7 @@ internal class ProjectResolutionFacade( val containingKtFile = it.containingKtFile val perFileCache = cache[containingKtFile] try { - perFileCache.getAnalysisResults(it) + perFileCache.getAnalysisResults(it, callback) } catch (e: Throwable) { if (e is ControlFlowException) { throw e diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ResolutionFacadeWithDebugInfo.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ResolutionFacadeWithDebugInfo.kt index 685dd37ef16..3ba69c97048 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ResolutionFacadeWithDebugInfo.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ResolutionFacadeWithDebugInfo.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.analyzer.ResolverForProject import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.idea.FrontendInternals +import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.caches.project.getNullableModuleInfo import org.jetbrains.kotlin.idea.resolve.ResolutionFacade @@ -52,9 +53,12 @@ private class ResolutionFacadeWithDebugInfo( } } - override fun analyzeWithAllCompilerChecks(elements: Collection): AnalysisResult { + override fun analyzeWithAllCompilerChecks( + elements: Collection, + callback: DiagnosticSink.DiagnosticsCallback? + ): AnalysisResult { return wrapExceptions({ ResolvingWhat(elements) }) { - delegate.analyzeWithAllCompilerChecks(elements) + delegate.analyzeWithAllCompilerChecks(elements, callback) } } diff --git a/plugins/scripting/scripting-ide-services/src/org/jetbrains/kotlin/scripting/ide_services/compiler/impl/KotlinResolutionFacadeForRepl.kt b/plugins/scripting/scripting-ide-services/src/org/jetbrains/kotlin/scripting/ide_services/compiler/impl/KotlinResolutionFacadeForRepl.kt index 218befbfda1..a4865652e55 100644 --- a/plugins/scripting/scripting-ide-services/src/org/jetbrains/kotlin/scripting/ide_services/compiler/impl/KotlinResolutionFacadeForRepl.kt +++ b/plugins/scripting/scripting-ide-services/src/org/jetbrains/kotlin/scripting/ide_services/compiler/impl/KotlinResolutionFacadeForRepl.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.container.ComponentProvider import org.jetbrains.kotlin.container.getService import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.idea.FrontendInternals import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.psi.KtDeclaration @@ -72,7 +73,10 @@ class KotlinResolutionFacadeForRepl( throw UnsupportedOperationException() } - override fun analyzeWithAllCompilerChecks(elements: Collection): AnalysisResult { + override fun analyzeWithAllCompilerChecks( + elements: Collection, + callback: DiagnosticSink.DiagnosticsCallback? + ): AnalysisResult { throw UnsupportedOperationException() }