mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 06:50:54 +07:00
[jvm] Remove unnecessary extension point for annotation suppressions
The extension point was used to run logic for various suppression annotations. Instead of running different logic based on the language, we can run the same logic for all languages. #IDEA-337709 GitOrigin-RevId: 7c51e3774d8d0c5232d37b817d1086ba4ebdda57
This commit is contained in:
committed by
intellij-monorepo-bot
parent
e9802d2cb8
commit
316a5db6c8
@@ -1,36 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInspection
|
||||
|
||||
import com.intellij.lang.LanguageExtension
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.util.IntellijInternalApi
|
||||
import org.jetbrains.annotations.ApiStatus.Internal
|
||||
import org.jetbrains.uast.UAnnotation
|
||||
import org.jetbrains.uast.UExpression
|
||||
|
||||
private val EP_NAME: ExtensionPointName<SuppressionAnnotationUtil> =
|
||||
ExtensionPointName.create("com.intellij.codeInspection.suppressionAnnotationUtil")
|
||||
|
||||
/**
|
||||
* Helper extension providing utility methods used by [com.intellij.codeInspection.SuppressionAnnotationInspection].
|
||||
*/
|
||||
@Internal
|
||||
@IntellijInternalApi
|
||||
interface SuppressionAnnotationUtil {
|
||||
companion object {
|
||||
@JvmField
|
||||
val extension = LanguageExtension<SuppressionAnnotationUtil>(EP_NAME.name)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if a given annotation is a suppression annotation in its language,
|
||||
* e.g. [SuppressWarnings] in Java or [Suppress] in Kotlin.
|
||||
*/
|
||||
fun isSuppressionAnnotation(annotation: UAnnotation): Boolean
|
||||
|
||||
/**
|
||||
* @return values of a suppression annotation attribute defining suppressed problem names.
|
||||
* Returned values should be [org.jetbrains.uast.UNamedExpression.expression].
|
||||
*/
|
||||
fun getSuppressionAnnotationAttributeExpressions(annotation: UAnnotation): List<UExpression>
|
||||
}
|
||||
@@ -9,11 +9,6 @@
|
||||
beanClass="com.intellij.lang.LanguageExtensionPoint">
|
||||
<with attribute="implementationClass" implements="com.intellij.codeInspection.sourceToSink.SourceToSinkProvider"/>
|
||||
</extensionPoint>
|
||||
<extensionPoint qualifiedName="com.intellij.codeInspection.suppressionAnnotationUtil"
|
||||
dynamic="true"
|
||||
beanClass="com.intellij.lang.LanguageExtensionPoint">
|
||||
<with attribute="implementationClass" implements="com.intellij.codeInspection.SuppressionAnnotationUtil"/>
|
||||
</extensionPoint>
|
||||
</extensionPoints>
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<!--Test frameworks-->
|
||||
@@ -163,7 +158,6 @@
|
||||
</extensions>
|
||||
<extensions defaultExtensionNs="com.intellij.codeInspection">
|
||||
<sourceToSinkProvider language="JAVA" implementationClass="com.intellij.codeInspection.sourceToSink.JavaSourceToSinkProvider"/>
|
||||
<suppressionAnnotationUtil language="JAVA" implementationClass="com.intellij.codeInspection.JavaSuppressionAnnotationUtil"/>
|
||||
</extensions>
|
||||
<actions>
|
||||
<group id="UastInternal" text="UAST" internal="true" popup="true">
|
||||
|
||||
@@ -13,18 +13,21 @@ import com.intellij.modcommand.ModPsiUpdater
|
||||
import com.intellij.modcommand.PsiUpdateModCommandQuickFix
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.psi.PsiAnnotation
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.psi.util.CachedValuesManager
|
||||
import com.intellij.psi.util.PsiModificationTracker
|
||||
import com.intellij.uast.UastHintedVisitorAdapter
|
||||
import org.jetbrains.annotations.VisibleForTesting
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.expressions.UInjectionHost
|
||||
import org.jetbrains.uast.visitor.AbstractUastNonRecursiveVisitor
|
||||
|
||||
private class SuppressAnnotationDescriptor(val pkg: String, val shortName: String, val attributeValue: String)
|
||||
|
||||
private val suppressAnnotations = listOf(
|
||||
SuppressAnnotationDescriptor("kotlin", "Suppress", "names"),
|
||||
SuppressAnnotationDescriptor("java.lang", "SuppressWarnings", "value")
|
||||
)
|
||||
|
||||
@VisibleForTesting
|
||||
class SuppressionAnnotationInspection : AbstractBaseUastLocalInspectionTool() {
|
||||
var myAllowedSuppressions: MutableList<String> = ArrayList()
|
||||
@@ -51,7 +54,6 @@ class SuppressionAnnotationInspection : AbstractBaseUastLocalInspectionTool() {
|
||||
}
|
||||
|
||||
private inner class SuppressionAnnotationVisitor(private val holder: ProblemsHolder) : AbstractUastNonRecursiveVisitor() {
|
||||
|
||||
override fun visitElement(node: UElement): Boolean {
|
||||
if (node is UComment) {
|
||||
return visitComment(node)
|
||||
@@ -96,13 +98,12 @@ class SuppressionAnnotationInspection : AbstractBaseUastLocalInspectionTool() {
|
||||
}
|
||||
|
||||
override fun visitAnnotation(node: UAnnotation): Boolean {
|
||||
val suppressionAnnotationUtil = SuppressionAnnotationUtil.extension.forLanguage(node.lang) ?: return false
|
||||
if (suppressionAnnotationUtil.isSuppressionAnnotation(node)) {
|
||||
val ids = getInspectionIdsSuppressedInAnnotation(node, suppressionAnnotationUtil)
|
||||
when {
|
||||
ids.isNotEmpty() && !myAllowedSuppressions.containsAll(ids) -> registerProblem(node, true)
|
||||
ids.isEmpty() -> registerProblem(node, false)
|
||||
}
|
||||
val suppressDescriptor = node.suppressDescriptor()
|
||||
if (suppressDescriptor == null) return true
|
||||
val suppressIds = node.suppressIds(suppressDescriptor.attributeValue)
|
||||
when {
|
||||
suppressIds.isNotEmpty() && !myAllowedSuppressions.containsAll(suppressIds) -> registerProblem(node, true)
|
||||
suppressIds.isEmpty() -> registerProblem(node, false)
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -151,8 +152,8 @@ class SuppressionAnnotationInspection : AbstractBaseUastLocalInspectionTool() {
|
||||
private fun getIds(psiElement: PsiElement): Collection<String>? {
|
||||
val annotation = psiElement.toUElement()?.getParentOfType<UAnnotation>(strict = false)
|
||||
if (annotation != null) {
|
||||
val suppressionAnnotationUtil = SuppressionAnnotationUtil.extension.forLanguage(annotation.lang) ?: return null
|
||||
return getInspectionIdsSuppressedInAnnotation(annotation, suppressionAnnotationUtil)
|
||||
val attributeValue = annotation.suppressDescriptor()?.attributeValue ?: return null
|
||||
return annotation.suppressIds(attributeValue)
|
||||
}
|
||||
else {
|
||||
val comment = psiElement.toUElement(UComment::class.java) ?: return null
|
||||
@@ -170,29 +171,16 @@ class SuppressionAnnotationInspection : AbstractBaseUastLocalInspectionTool() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getInspectionIdsSuppressedInAnnotation(annotation: UAnnotation,
|
||||
suppressionAnnotationUtil: SuppressionAnnotationUtil): List<String> {
|
||||
val sourcePsi = annotation.sourcePsi ?: return emptyList()
|
||||
return CachedValuesManager.getCachedValue(sourcePsi) {
|
||||
CachedValueProvider.Result.create(
|
||||
doGetInspectionIdsSuppressedInAnnotation(annotation, suppressionAnnotationUtil),
|
||||
PsiModificationTracker.MODIFICATION_COUNT
|
||||
)
|
||||
}
|
||||
private fun UAnnotation.suppressDescriptor(): SuppressAnnotationDescriptor? {
|
||||
val shortName = uastAnchor?.name ?: return null
|
||||
if (suppressAnnotations.none { descr -> descr.shortName == shortName }) return null
|
||||
return suppressAnnotations.firstOrNull { descr -> "${descr.pkg}.${descr.shortName}" == qualifiedName }
|
||||
}
|
||||
|
||||
// do not move it into visitor class, as it will cause CachedValue-related exceptions
|
||||
private fun doGetInspectionIdsSuppressedInAnnotation(annotation: UAnnotation,
|
||||
suppressionAnnotationUtil: SuppressionAnnotationUtil): List<String> {
|
||||
val expressions = suppressionAnnotationUtil.getSuppressionAnnotationAttributeExpressions(annotation)
|
||||
return expressions.flatMap { getInspectionIdsSuppressedInAnnotation(it) }
|
||||
}
|
||||
|
||||
private fun getInspectionIdsSuppressedInAnnotation(expression: UExpression): List<String> {
|
||||
return when (expression) {
|
||||
is UInjectionHost, is UReferenceExpression -> listOfNotNull(expression.evaluateString())
|
||||
is UCallExpression -> expression.valueArguments.flatMap { getInspectionIdsSuppressedInAnnotation(it) }
|
||||
else -> emptyList()
|
||||
private fun UAnnotation.suppressIds(attributeName: String): List<String> = flattenedAttributeValues(attributeName).mapNotNull {
|
||||
when (it) {
|
||||
is UInjectionHost, is UReferenceExpression -> it.evaluateString()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,18 +193,4 @@ private fun getIdsFromComment(commentText: String): List<String>? {
|
||||
else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
internal class JavaSuppressionAnnotationUtil : SuppressionAnnotationUtil {
|
||||
override fun isSuppressionAnnotation(annotation: UAnnotation): Boolean {
|
||||
val psiAnnotation = annotation.sourcePsi as? PsiAnnotation ?: return false
|
||||
val referenceText = psiAnnotation.nameReferenceElement?.text ?: return false
|
||||
return "SuppressWarnings" == referenceText || BatchSuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME == referenceText
|
||||
}
|
||||
|
||||
override fun getSuppressionAnnotationAttributeExpressions(annotation: UAnnotation): List<UExpression> {
|
||||
return annotation.attributeValues
|
||||
.filter { it.name == null || it.name == "value" }
|
||||
.map { it.expression }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,15 +88,6 @@ class JavaSuppressionAnnotationInspectionTest : SuppressionAnnotationInspectionT
|
||||
""".trimIndent(), "PublicField")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow multiple suppressions from annotation`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.JAVA, """
|
||||
public class A {
|
||||
@SuppressWarnings("Public<caret>Field", "HardCodedStringLiteral")
|
||||
public String s = "test";
|
||||
}
|
||||
""".trimIndent(), "PublicField", "HardCodedStringLiteral")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow multiple suppressions from annotation when array form used`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.JAVA, """
|
||||
public class A {
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.inspections
|
||||
|
||||
import com.intellij.codeInspection.SuppressionAnnotationUtil
|
||||
import org.jetbrains.uast.UAnnotation
|
||||
import org.jetbrains.uast.UExpression
|
||||
|
||||
internal class KotlinSuppressionAnnotationUtil : SuppressionAnnotationUtil {
|
||||
|
||||
private val suppressionAnnotationClassQualifiedName = Suppress::class.java.name
|
||||
|
||||
override fun isSuppressionAnnotation(annotation: UAnnotation): Boolean {
|
||||
return annotation.sourcePsi?.text?.contains("Suppress") == true && // avoid resolving
|
||||
annotation.qualifiedName == suppressionAnnotationClassQualifiedName
|
||||
}
|
||||
|
||||
override fun getSuppressionAnnotationAttributeExpressions(annotation: UAnnotation): List<UExpression> {
|
||||
return annotation.attributeValues
|
||||
.filter { it.name == null || it.name == "names" }
|
||||
.map { it.expression }
|
||||
}
|
||||
}
|
||||
@@ -117,11 +117,6 @@
|
||||
<documentationProvider implementation="org.jetbrains.kotlin.idea.KotlinDocumentationProvider"/>
|
||||
|
||||
<definitionsScopedSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDefinitionsSearcher"/>
|
||||
|
||||
<codeInspection.suppressionAnnotationUtil
|
||||
language="kotlin"
|
||||
implementationClass="org.jetbrains.kotlin.idea.inspections.KotlinSuppressionAnnotationUtil"/>
|
||||
|
||||
</extensions>
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user