Allow to check suppression by string keys
This commit is contained in:
committed by
Nikolay Krasko
parent
20379028e8
commit
b61b4e1c90
@@ -30,6 +30,11 @@ public abstract class DiagnosticFactory<D extends Diagnostic> {
|
|||||||
this.severity = severity;
|
this.severity = severity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected DiagnosticFactory(@NotNull String name, @NotNull Severity severity) {
|
||||||
|
this.name = name;
|
||||||
|
this.severity = severity;
|
||||||
|
}
|
||||||
|
|
||||||
/*package*/ void setName(@NotNull String name) {
|
/*package*/ void setName(@NotNull String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -30,13 +30,13 @@ import java.util.Collection;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
public class DiagnosticsWithSuppression implements Diagnostics {
|
public class DiagnosticsWithSuppression implements Diagnostics {
|
||||||
private final SuppressionManager suppressionManager;
|
private final BindingContextSuppressionManager suppressionManager;
|
||||||
private final Collection<Diagnostic> diagnostics;
|
private final Collection<Diagnostic> diagnostics;
|
||||||
private final DiagnosticsElementsCache elementsCache;
|
private final DiagnosticsElementsCache elementsCache;
|
||||||
|
|
||||||
public DiagnosticsWithSuppression(@NotNull BindingContext context, @NotNull Collection<Diagnostic> diagnostics) {
|
public DiagnosticsWithSuppression(@NotNull BindingContext context, @NotNull Collection<Diagnostic> diagnostics) {
|
||||||
this.diagnostics = diagnostics;
|
this.diagnostics = diagnostics;
|
||||||
this.suppressionManager = new SuppressionManager(context);
|
this.suppressionManager = new BindingContextSuppressionManager(context);
|
||||||
this.elementsCache = new DiagnosticsElementsCache(this, suppressionManager.getFilter());
|
this.elementsCache = new DiagnosticsElementsCache(this, suppressionManager.getFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+57
-28
@@ -19,10 +19,13 @@ package org.jetbrains.kotlin.resolve.diagnostics
|
|||||||
import com.google.common.collect.ImmutableSet
|
import com.google.common.collect.ImmutableSet
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import com.intellij.openapi.extensions.ExtensionPointName
|
import com.intellij.openapi.extensions.ExtensionPointName
|
||||||
|
import com.intellij.openapi.util.TextRange
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.util.containers.ConcurrentWeakValueHashMap
|
import com.intellij.util.containers.ConcurrentWeakValueHashMap
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
|
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||||
import org.jetbrains.kotlin.diagnostics.Severity
|
import org.jetbrains.kotlin.diagnostics.Severity
|
||||||
import org.jetbrains.kotlin.psi.KtAnnotated
|
import org.jetbrains.kotlin.psi.KtAnnotated
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
@@ -49,7 +52,7 @@ interface DiagnosticSuppressor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SuppressionManager(val context: BindingContext) {
|
abstract class SuppressionManager {
|
||||||
private val LOG = Logger.getInstance(DiagnosticsWithSuppression::class.java)
|
private val LOG = Logger.getInstance(DiagnosticsWithSuppression::class.java)
|
||||||
|
|
||||||
private val ADDITIONAL_SUPPRESS_STRING_PROVIDERS = ExtensionProvider.create(SuppressStringProvider.EP_NAME)
|
private val ADDITIONAL_SUPPRESS_STRING_PROVIDERS = ExtensionProvider.create(SuppressStringProvider.EP_NAME)
|
||||||
@@ -58,27 +61,33 @@ class SuppressionManager(val context: BindingContext) {
|
|||||||
// The cache is weak: we're OK with losing it
|
// The cache is weak: we're OK with losing it
|
||||||
private val suppressors = ConcurrentWeakValueHashMap<KtAnnotated, Suppressor>()
|
private val suppressors = ConcurrentWeakValueHashMap<KtAnnotated, Suppressor>()
|
||||||
|
|
||||||
public val filter: (Diagnostic) -> Boolean = { diagnostic: Diagnostic -> !isSuppressed(diagnostic) }
|
val filter: (Diagnostic) -> Boolean = { diagnostic: Diagnostic -> !isSuppressed(diagnostic) }
|
||||||
|
|
||||||
private fun isSuppressed(diagnostic: Diagnostic): Boolean {
|
fun isSuppressed(psiElement: PsiElement, suppressionKey: String, severity: Severity) =
|
||||||
val element = diagnostic.psiElement
|
isSuppressed(StringSuppressRequest(psiElement, severity, suppressionKey.toLowerCase()))
|
||||||
|
|
||||||
|
fun isSuppressed(diagnostic: Diagnostic): Boolean = isSuppressed(DiagnosticSuppressRequest(diagnostic))
|
||||||
|
|
||||||
|
private fun isSuppressed(request: SuppressRequest): Boolean {
|
||||||
// If diagnostics are reported in a synthetic file generated by KtPsiFactory (dummy.kt),
|
// If diagnostics are reported in a synthetic file generated by KtPsiFactory (dummy.kt),
|
||||||
// there's no point to present such diagnostics to the user, because the user didn't write this code
|
// there's no point to present such diagnostics to the user, because the user didn't write this code
|
||||||
val file = element.containingFile
|
val file = request.element.containingFile
|
||||||
if (file is KtFile) {
|
if (file is KtFile) {
|
||||||
if (file.doNotAnalyze != null) return true
|
if (file.doNotAnalyze != null) return true
|
||||||
}
|
}
|
||||||
|
|
||||||
for (suppressor in DIAGNOSTIC_SUPPRESSORS.get()) {
|
if (request is DiagnosticSuppressRequest) {
|
||||||
if (suppressor.isSuppressed(diagnostic)) return true
|
for (suppressor in DIAGNOSTIC_SUPPRESSORS.get()) {
|
||||||
|
if (suppressor.isSuppressed(request.diagnostic)) return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val annotated = KtStubbedPsiUtil.getPsiOrStubParent(element, KtAnnotated::class.java, false) ?: return false
|
val annotated = KtStubbedPsiUtil.getPsiOrStubParent(request.element, KtAnnotated::class.java, false) ?: return false
|
||||||
|
|
||||||
return isSuppressedByAnnotated(diagnostic, annotated, 0)
|
return isSuppressedByAnnotated(request.suppressKey, request.severity, annotated, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The cache is optimized for the case where no warnings are suppressed (most frequent one)
|
The cache is optimized for the case where no warnings are suppressed (most frequent one)
|
||||||
|
|
||||||
@@ -108,7 +117,7 @@ class SuppressionManager(val context: BindingContext) {
|
|||||||
|
|
||||||
This way we need no more lookups than the number of suppress() annotations from here to the root.
|
This way we need no more lookups than the number of suppress() annotations from here to the root.
|
||||||
*/
|
*/
|
||||||
private fun isSuppressedByAnnotated(diagnostic: Diagnostic, annotated: KtAnnotated, debugDepth: Int): Boolean {
|
protected fun isSuppressedByAnnotated(suppressionKey: String, severity: Severity, annotated: KtAnnotated, debugDepth: Int): Boolean {
|
||||||
if (LOG.isDebugEnabled) {
|
if (LOG.isDebugEnabled) {
|
||||||
LOG.debug("Annotated: ", annotated.name)
|
LOG.debug("Annotated: ", annotated.name)
|
||||||
LOG.debug("Depth: ", debugDepth)
|
LOG.debug("Depth: ", debugDepth)
|
||||||
@@ -116,11 +125,11 @@ class SuppressionManager(val context: BindingContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val suppressor = getOrCreateSuppressor(annotated)
|
val suppressor = getOrCreateSuppressor(annotated)
|
||||||
if (suppressor.isSuppressed(diagnostic)) return true
|
if (suppressor.isSuppressed(suppressionKey, severity)) return true
|
||||||
|
|
||||||
val annotatedAbove = KtStubbedPsiUtil.getPsiOrStubParent(suppressor.annotatedElement, KtAnnotated::class.java, true) ?: return false
|
val annotatedAbove = KtStubbedPsiUtil.getPsiOrStubParent(suppressor.annotatedElement, KtAnnotated::class.java, true) ?: return false
|
||||||
|
|
||||||
val suppressed = isSuppressedByAnnotated(diagnostic, annotatedAbove, debugDepth + 1)
|
val suppressed = isSuppressedByAnnotated(suppressionKey, severity, annotatedAbove, debugDepth + 1)
|
||||||
val suppressorAbove = suppressors[annotatedAbove]
|
val suppressorAbove = suppressors[annotatedAbove]
|
||||||
if (suppressorAbove != null && suppressorAbove.dominates(suppressor)) {
|
if (suppressorAbove != null && suppressorAbove.dominates(suppressor)) {
|
||||||
suppressors.put(annotated, suppressorAbove)
|
suppressors.put(annotated, suppressorAbove)
|
||||||
@@ -147,28 +156,18 @@ class SuppressionManager(val context: BindingContext) {
|
|||||||
return suppressor
|
return suppressor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract fun getSuppressionAnnotations(annotated: KtAnnotated): List<AnnotationDescriptor>
|
||||||
|
|
||||||
private fun getSuppressingStrings(annotated: KtAnnotated): Set<String> {
|
private fun getSuppressingStrings(annotated: KtAnnotated): Set<String> {
|
||||||
val builder = ImmutableSet.builder<String>()
|
val builder = ImmutableSet.builder<String>()
|
||||||
|
for (annotationDescriptor in getSuppressionAnnotations(annotated)) {
|
||||||
val descriptor = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, annotated)
|
processAnnotation(builder, annotationDescriptor)
|
||||||
|
|
||||||
if (descriptor != null) {
|
|
||||||
for (annotationDescriptor in descriptor.annotations) {
|
|
||||||
processAnnotation(builder, annotationDescriptor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (annotationEntry in annotated.annotationEntries) {
|
|
||||||
val annotationDescriptor = context.get(BindingContext.ANNOTATION, annotationEntry)
|
|
||||||
processAnnotation(builder, annotationDescriptor)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.build()
|
return builder.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processAnnotation(builder: ImmutableSet.Builder<String>, annotationDescriptor: AnnotationDescriptor?) {
|
private fun processAnnotation(builder: ImmutableSet.Builder<String>, annotationDescriptor: AnnotationDescriptor) {
|
||||||
if (annotationDescriptor == null) return
|
|
||||||
|
|
||||||
for (suppressStringProvider in ADDITIONAL_SUPPRESS_STRING_PROVIDERS.get()) {
|
for (suppressStringProvider in ADDITIONAL_SUPPRESS_STRING_PROVIDERS.get()) {
|
||||||
builder.addAll(suppressStringProvider[annotationDescriptor])
|
builder.addAll(suppressStringProvider[annotationDescriptor])
|
||||||
}
|
}
|
||||||
@@ -241,4 +240,34 @@ class SuppressionManager(val context: BindingContext) {
|
|||||||
return other is EmptySuppressor
|
return other is EmptySuppressor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private interface SuppressRequest {
|
||||||
|
val element: PsiElement
|
||||||
|
val severity: Severity
|
||||||
|
val suppressKey: String
|
||||||
|
}
|
||||||
|
|
||||||
|
private class StringSuppressRequest(
|
||||||
|
override val element: PsiElement,
|
||||||
|
override val severity: Severity,
|
||||||
|
override val suppressKey: String) : SuppressRequest
|
||||||
|
|
||||||
|
private class DiagnosticSuppressRequest(val diagnostic: Diagnostic) : SuppressRequest {
|
||||||
|
override val element: PsiElement get() = diagnostic.psiElement
|
||||||
|
override val severity: Severity get() = diagnostic.severity
|
||||||
|
override val suppressKey: String get() = getDiagnosticSuppressKey(diagnostic)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BindingContextSuppressionManager(val context: BindingContext) : SuppressionManager() {
|
||||||
|
override fun getSuppressionAnnotations(annotated: KtAnnotated): List<AnnotationDescriptor> {
|
||||||
|
val descriptor = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, annotated)
|
||||||
|
|
||||||
|
if (descriptor != null) {
|
||||||
|
return descriptor.annotations.toList()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return annotated.annotationEntries.map { context.get(BindingContext.ANNOTATION, it) }.filterNotNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user