From b61b4e1c902946676c0b52e1438fb773eb61061f Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Mon, 30 Nov 2015 17:54:59 +0300 Subject: [PATCH] Allow to check suppression by string keys --- .../kotlin/diagnostics/DiagnosticFactory.java | 5 ++ .../DiagnosticsWithSuppression.java | 4 +- .../resolve/diagnostics/SuppressionManager.kt | 85 +++++++++++++------ 3 files changed, 64 insertions(+), 30 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/DiagnosticFactory.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/DiagnosticFactory.java index ac57634fb70..63e1eca9126 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/DiagnosticFactory.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/DiagnosticFactory.java @@ -30,6 +30,11 @@ public abstract class DiagnosticFactory { 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; } 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 2b144f58f5e..3878ff32195 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/DiagnosticsWithSuppression.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/DiagnosticsWithSuppression.java @@ -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 diagnostics; private final DiagnosticsElementsCache elementsCache; public DiagnosticsWithSuppression(@NotNull BindingContext context, @NotNull Collection diagnostics) { this.diagnostics = diagnostics; - this.suppressionManager = new SuppressionManager(context); + this.suppressionManager = new BindingContextSuppressionManager(context); this.elementsCache = new DiagnosticsElementsCache(this, suppressionManager.getFilter()); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/SuppressionManager.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/SuppressionManager.kt index aa80e53b964..1d79553a890 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/SuppressionManager.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/SuppressionManager.kt @@ -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() - 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 + private fun getSuppressingStrings(annotated: KtAnnotated): Set { val builder = ImmutableSet.builder() - - 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, annotationDescriptor: AnnotationDescriptor?) { - if (annotationDescriptor == null) return - + private fun processAnnotation(builder: ImmutableSet.Builder, 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 { + 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() + } + } } \ No newline at end of file