[Frontend] Make DiagnosticSuppressor a project-level extension
Originally it was an application-level component, which caused non-trivial
logic and cognitive load to carefully handle those extensions to avoid
memory leaks.
6740a596 introduced a way to easily register `DiagnosticSuppressor` to
project, and this commit continues this work, making it a proper
project-level extension
A lot of changes caused by the fact, that this extension is needed to be
obtained from `BindingContext` (see `BindingContextSuppressCache` and
its usages), so almost all changes are introducing `Project` to
`BindingContext`
^KT-66449 Fixed
This commit is contained in:
committed by
Space Team
parent
a552238874
commit
d352cc9d96
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.cfg.pseudocode;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.cfg.ControlFlowProcessor;
|
||||
@@ -95,6 +96,12 @@ public class PseudocodeUtil {
|
||||
public boolean wantsDiagnostics() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Project getProject() {
|
||||
return bindingContext.getProject();
|
||||
}
|
||||
};
|
||||
return new ControlFlowProcessor(mockTrace, languageVersionSettings).generatePseudocode(declaration);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.resolve;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import kotlin.Pair;
|
||||
@@ -89,8 +90,17 @@ public interface BindingContext {
|
||||
public void addOwnDataTo(@NotNull BindingTrace trace, boolean commitDiagnostics) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Project getProject() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
@Nullable
|
||||
Project getProject();
|
||||
|
||||
WritableSlice<KtAnnotationEntry, AnnotationDescriptor> ANNOTATION = Slices.createSimpleSlice();
|
||||
|
||||
WritableSlice<KtExpression, CompileTimeConstant<?>> COMPILE_TIME_VALUE = new BasicWritableSlice<>(COMPILE_TIME_VALUE_REWRITE_POLICY);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink;
|
||||
@@ -30,6 +31,9 @@ public interface BindingTrace extends DiagnosticSink {
|
||||
|
||||
@NotNull
|
||||
BindingContext getBindingContext();
|
||||
|
||||
@Nullable
|
||||
Project getProject();
|
||||
|
||||
<K, V> void record(WritableSlice<K, V> slice, K key, V value);
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
@@ -42,6 +43,7 @@ public class BindingTraceContext implements BindingTrace {
|
||||
|
||||
private final MutableSlicedMap map;
|
||||
private final MutableDiagnosticsWithSuppression mutableDiagnostics;
|
||||
private final Project project;
|
||||
|
||||
private final boolean isValidationEnabled;
|
||||
|
||||
@@ -85,36 +87,43 @@ public class BindingTraceContext implements BindingTrace {
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Project getProject() {
|
||||
return project;
|
||||
}
|
||||
};
|
||||
|
||||
public BindingTraceContext() {
|
||||
this(false);
|
||||
public BindingTraceContext(Project project) {
|
||||
this(false, project);
|
||||
}
|
||||
|
||||
public BindingTraceContext(boolean allowSliceRewrite) {
|
||||
this(BindingTraceFilter.Companion.getACCEPT_ALL(), allowSliceRewrite);
|
||||
public BindingTraceContext(boolean allowSliceRewrite, Project project) {
|
||||
this(BindingTraceFilter.Companion.getACCEPT_ALL(), allowSliceRewrite, project);
|
||||
}
|
||||
|
||||
public BindingTraceContext(BindingTraceFilter filter, boolean allowSliceRewrite) {
|
||||
this(filter, allowSliceRewrite, VALIDATION);
|
||||
public BindingTraceContext(BindingTraceFilter filter, boolean allowSliceRewrite, Project project) {
|
||||
this(filter, allowSliceRewrite, VALIDATION, project);
|
||||
}
|
||||
|
||||
public BindingTraceContext(BindingTraceFilter filter, boolean allowSliceRewrite, boolean isValidationEnabled) {
|
||||
this(TRACK_REWRITES && !allowSliceRewrite ? new TrackingSlicedMap(TRACK_WITH_STACK_TRACES) : new SlicedMapImpl(allowSliceRewrite), filter, isValidationEnabled);
|
||||
public BindingTraceContext(BindingTraceFilter filter, boolean allowSliceRewrite, boolean isValidationEnabled, Project project) {
|
||||
this(TRACK_REWRITES && !allowSliceRewrite ? new TrackingSlicedMap(TRACK_WITH_STACK_TRACES) : new SlicedMapImpl(allowSliceRewrite), filter, isValidationEnabled, project);
|
||||
}
|
||||
|
||||
private BindingTraceContext(@NotNull MutableSlicedMap map, BindingTraceFilter filter, boolean isValidationEnabled) {
|
||||
private BindingTraceContext(@NotNull MutableSlicedMap map, BindingTraceFilter filter, boolean isValidationEnabled, Project project) {
|
||||
this.map = map;
|
||||
this.mutableDiagnostics =
|
||||
filter.getIgnoreDiagnostics()
|
||||
? null
|
||||
: new MutableDiagnosticsWithSuppression(new BindingContextSuppressCache(bindingContext), Diagnostics.Companion.getEMPTY());
|
||||
this.isValidationEnabled = isValidationEnabled;
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public static BindingTraceContext createTraceableBindingTrace() {
|
||||
return new BindingTraceContext(new TrackingSlicedMap(TRACK_WITH_STACK_TRACES), BindingTraceFilter.Companion.getACCEPT_ALL(), VALIDATION);
|
||||
public static BindingTraceContext createTraceableBindingTrace(Project project) {
|
||||
return new BindingTraceContext(new TrackingSlicedMap(TRACK_WITH_STACK_TRACES), BindingTraceFilter.Companion.getACCEPT_ALL(), VALIDATION, project);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -125,6 +134,11 @@ public class BindingTraceContext implements BindingTrace {
|
||||
mutableDiagnostics.report(diagnostic);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Project getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
public void clearDiagnostics() {
|
||||
if (mutableDiagnostics != null) {
|
||||
mutableDiagnostics.clear();
|
||||
|
||||
@@ -27,6 +27,6 @@ interface CodeAnalyzerInitializer {
|
||||
}
|
||||
}
|
||||
|
||||
class DummyCodeAnalyzerInitializer : CodeAnalyzerInitializer {
|
||||
override fun createTrace(): BindingTrace = BindingTraceContext(true)
|
||||
class DummyCodeAnalyzerInitializer(val project: Project) : CodeAnalyzerInitializer {
|
||||
override fun createTrace(): BindingTrace = BindingTraceContext(/* allowSliceRewrite = */ true, project)
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve
|
||||
import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice
|
||||
import org.jetbrains.kotlin.util.slicedMap.WritableSlice
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.openapi.util.ModificationTracker
|
||||
@@ -66,6 +67,10 @@ class CompositeBindingContext private constructor(
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
override fun getProject(): Project? {
|
||||
return delegates.firstOrNull()?.project
|
||||
}
|
||||
|
||||
private class CompositeDiagnostics(
|
||||
private val delegates: List<Diagnostics>
|
||||
) : Diagnostics {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.resolve
|
||||
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
@@ -66,6 +67,10 @@ open class DelegatingBindingTrace(
|
||||
override fun <K, V> getSliceContents(slice: ReadOnlySlice<K, V>): ImmutableMap<K, V> {
|
||||
return ImmutableMap.copyOf(parentContext.getSliceContents(slice) + map.getSliceContents(slice))
|
||||
}
|
||||
|
||||
override fun getProject(): Project? {
|
||||
return this@DelegatingBindingTrace.getProject()
|
||||
}
|
||||
}
|
||||
|
||||
private val bindingContext = MyBindingContext()
|
||||
@@ -176,4 +181,8 @@ open class DelegatingBindingTrace(
|
||||
override fun wantsDiagnostics(): Boolean = mutableDiagnostics != null
|
||||
|
||||
override fun toString(): String = name
|
||||
|
||||
override fun getProject(): Project? {
|
||||
return parentContext.project
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.util.SmartFMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -102,4 +103,10 @@ public class ObservableBindingTrace implements BindingTrace {
|
||||
public String toString() {
|
||||
return "ObservableTrace over " + originalTrace.toString();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Project getProject() {
|
||||
return originalTrace.getProject();
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve.diagnostics
|
||||
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
@@ -30,7 +31,6 @@ 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
|
||||
import org.jetbrains.kotlin.util.ExtensionProvider
|
||||
|
||||
interface DiagnosticSuppressor {
|
||||
fun isSuppressed(diagnostic: Diagnostic): Boolean
|
||||
@@ -48,9 +48,9 @@ interface DiagnosticSuppressor {
|
||||
}
|
||||
}
|
||||
|
||||
abstract class KotlinSuppressCache : AbstractKotlinSuppressCache<PsiElement>() {
|
||||
abstract class KotlinSuppressCache(project: Project?) : AbstractKotlinSuppressCache<PsiElement>() {
|
||||
|
||||
private val diagnosticSuppressors = ExtensionProvider.create(DiagnosticSuppressor.extensionPointName)
|
||||
private val diagnosticSuppressors: List<DiagnosticSuppressor> = project?.let { DiagnosticSuppressor.getInstances(it) } ?: emptyList()
|
||||
|
||||
val filter: (Diagnostic) -> Boolean = { diagnostic: Diagnostic ->
|
||||
!isSuppressed(DiagnosticSuppressRequest(diagnostic))
|
||||
@@ -99,7 +99,7 @@ abstract class KotlinSuppressCache : AbstractKotlinSuppressCache<PsiElement>() {
|
||||
}
|
||||
|
||||
if (request is DiagnosticSuppressRequest) {
|
||||
for (suppressor in diagnosticSuppressors.get()) {
|
||||
for (suppressor in diagnosticSuppressors) {
|
||||
if (isSuppressedByExtension(suppressor, request.diagnostic)) return true
|
||||
}
|
||||
}
|
||||
@@ -122,7 +122,7 @@ abstract class KotlinSuppressCache : AbstractKotlinSuppressCache<PsiElement>() {
|
||||
}
|
||||
}
|
||||
|
||||
class BindingContextSuppressCache(val context: BindingContext) : KotlinSuppressCache() {
|
||||
class BindingContextSuppressCache(val context: BindingContext) : KotlinSuppressCache(context.project) {
|
||||
override fun getSuppressionAnnotations(annotated: PsiElement): List<AnnotationDescriptor> {
|
||||
val descriptor = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, annotated)
|
||||
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtTreeVisitorVoid
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
|
||||
class OnDemandSuppressCache(private val context: BindingContext) : KotlinSuppressCache() {
|
||||
class OnDemandSuppressCache(private val context: BindingContext) : KotlinSuppressCache(context.project) {
|
||||
private val processedRoots = mutableSetOf<KtFile>()
|
||||
|
||||
private val storage = mutableMapOf<PsiElement, List<AnnotationDescriptor>>()
|
||||
|
||||
+9
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.storage
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
@@ -53,6 +54,10 @@ class LockBasedLazyResolveStorageManager(private val storageManager: StorageMana
|
||||
|
||||
@TestOnly
|
||||
override fun <K, V> getSliceContents(slice: ReadOnlySlice<K, V>) = storageManager.compute { context.getSliceContents<K, V>(slice) }
|
||||
|
||||
override fun getProject(): Project? {
|
||||
return context.project
|
||||
}
|
||||
}
|
||||
|
||||
private class LockProtectedTrace(private val storageManager: StorageManager, private val trace: BindingTrace) : BindingTrace {
|
||||
@@ -87,5 +92,9 @@ class LockBasedLazyResolveStorageManager(private val storageManager: StorageMana
|
||||
override fun toString(): String {
|
||||
return "Lock-protected trace of LockBasedLazyResolveStorageManager $storageManager"
|
||||
}
|
||||
|
||||
override fun getProject(): Project? {
|
||||
return trace.project
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.util
|
||||
|
||||
import com.intellij.openapi.application.Application
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
open class MappedExtensionProvider<T : Any, out R>
|
||||
protected constructor(
|
||||
private val epName: ExtensionPointName<T>,
|
||||
private val map: (List<T>) -> R
|
||||
) {
|
||||
private var cached = WeakReference<Pair<Application, R>>(null)
|
||||
|
||||
fun get(): R {
|
||||
val cached = cached.get() ?: return update()
|
||||
val (app, extensions) = cached
|
||||
return if (app == ApplicationManager.getApplication()) {
|
||||
extensions
|
||||
} else {
|
||||
update()
|
||||
}
|
||||
}
|
||||
|
||||
private fun update(): R {
|
||||
val newVal = ApplicationManager.getApplication().let { app ->
|
||||
Pair(app, map(app.extensionArea.getExtensionPoint(epName).extensionList))
|
||||
}
|
||||
cached = WeakReference(newVal)
|
||||
return newVal.second
|
||||
}
|
||||
}
|
||||
|
||||
class ExtensionProvider<T : Any>(epName: ExtensionPointName<T>) : MappedExtensionProvider<T, List<T>>(epName, { it }) {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun <T : Any> create(epName: ExtensionPointName<T>): ExtensionProvider<T> = ExtensionProvider(epName)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user