Allow to check suppression by string keys

This commit is contained in:
Nikolay Krasko
2015-11-30 17:54:59 +03:00
committed by Nikolay Krasko
parent 20379028e8
commit b61b4e1c90
3 changed files with 64 additions and 30 deletions
@@ -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;
}
@@ -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());
}
@@ -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()
}
}
}