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;
|
||||
}
|
||||
|
||||
protected DiagnosticFactory(@NotNull String name, @NotNull Severity severity) {
|
||||
this.name = name;
|
||||
this.severity = severity;
|
||||
}
|
||||
|
||||
/*package*/ void setName(@NotNull String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
+2
-2
@@ -30,13 +30,13 @@ import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class DiagnosticsWithSuppression implements Diagnostics {
|
||||
private final SuppressionManager suppressionManager;
|
||||
private final BindingContextSuppressionManager suppressionManager;
|
||||
private final Collection<Diagnostic> diagnostics;
|
||||
private final DiagnosticsElementsCache elementsCache;
|
||||
|
||||
public DiagnosticsWithSuppression(@NotNull BindingContext context, @NotNull Collection<Diagnostic> diagnostics) {
|
||||
this.diagnostics = diagnostics;
|
||||
this.suppressionManager = new SuppressionManager(context);
|
||||
this.suppressionManager = new BindingContextSuppressionManager(context);
|
||||
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.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.util.containers.ConcurrentWeakValueHashMap
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||
import org.jetbrains.kotlin.diagnostics.Severity
|
||||
import org.jetbrains.kotlin.psi.KtAnnotated
|
||||
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 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
|
||||
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 {
|
||||
val element = diagnostic.psiElement
|
||||
fun isSuppressed(psiElement: PsiElement, suppressionKey: String, severity: Severity) =
|
||||
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),
|
||||
// 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.doNotAnalyze != null) return true
|
||||
}
|
||||
|
||||
for (suppressor in DIAGNOSTIC_SUPPRESSORS.get()) {
|
||||
if (suppressor.isSuppressed(diagnostic)) return true
|
||||
if (request is DiagnosticSuppressRequest) {
|
||||
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)
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
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) {
|
||||
LOG.debug("Annotated: ", annotated.name)
|
||||
LOG.debug("Depth: ", debugDepth)
|
||||
@@ -116,11 +125,11 @@ class SuppressionManager(val context: BindingContext) {
|
||||
}
|
||||
|
||||
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 suppressed = isSuppressedByAnnotated(diagnostic, annotatedAbove, debugDepth + 1)
|
||||
val suppressed = isSuppressedByAnnotated(suppressionKey, severity, annotatedAbove, debugDepth + 1)
|
||||
val suppressorAbove = suppressors[annotatedAbove]
|
||||
if (suppressorAbove != null && suppressorAbove.dominates(suppressor)) {
|
||||
suppressors.put(annotated, suppressorAbove)
|
||||
@@ -147,28 +156,18 @@ class SuppressionManager(val context: BindingContext) {
|
||||
return suppressor
|
||||
}
|
||||
|
||||
abstract fun getSuppressionAnnotations(annotated: KtAnnotated): List<AnnotationDescriptor>
|
||||
|
||||
private fun getSuppressingStrings(annotated: KtAnnotated): Set<String> {
|
||||
val builder = ImmutableSet.builder<String>()
|
||||
|
||||
val descriptor = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, annotated)
|
||||
|
||||
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)
|
||||
}
|
||||
for (annotationDescriptor in getSuppressionAnnotations(annotated)) {
|
||||
processAnnotation(builder, annotationDescriptor)
|
||||
}
|
||||
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
private fun processAnnotation(builder: ImmutableSet.Builder<String>, annotationDescriptor: AnnotationDescriptor?) {
|
||||
if (annotationDescriptor == null) return
|
||||
|
||||
private fun processAnnotation(builder: ImmutableSet.Builder<String>, annotationDescriptor: AnnotationDescriptor) {
|
||||
for (suppressStringProvider in ADDITIONAL_SUPPRESS_STRING_PROVIDERS.get()) {
|
||||
builder.addAll(suppressStringProvider[annotationDescriptor])
|
||||
}
|
||||
@@ -241,4 +240,34 @@ class SuppressionManager(val context: BindingContext) {
|
||||
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