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">
|
beanClass="com.intellij.lang.LanguageExtensionPoint">
|
||||||
<with attribute="implementationClass" implements="com.intellij.codeInspection.sourceToSink.SourceToSinkProvider"/>
|
<with attribute="implementationClass" implements="com.intellij.codeInspection.sourceToSink.SourceToSinkProvider"/>
|
||||||
</extensionPoint>
|
</extensionPoint>
|
||||||
<extensionPoint qualifiedName="com.intellij.codeInspection.suppressionAnnotationUtil"
|
|
||||||
dynamic="true"
|
|
||||||
beanClass="com.intellij.lang.LanguageExtensionPoint">
|
|
||||||
<with attribute="implementationClass" implements="com.intellij.codeInspection.SuppressionAnnotationUtil"/>
|
|
||||||
</extensionPoint>
|
|
||||||
</extensionPoints>
|
</extensionPoints>
|
||||||
<extensions defaultExtensionNs="com.intellij">
|
<extensions defaultExtensionNs="com.intellij">
|
||||||
<!--Test frameworks-->
|
<!--Test frameworks-->
|
||||||
@@ -163,7 +158,6 @@
|
|||||||
</extensions>
|
</extensions>
|
||||||
<extensions defaultExtensionNs="com.intellij.codeInspection">
|
<extensions defaultExtensionNs="com.intellij.codeInspection">
|
||||||
<sourceToSinkProvider language="JAVA" implementationClass="com.intellij.codeInspection.sourceToSink.JavaSourceToSinkProvider"/>
|
<sourceToSinkProvider language="JAVA" implementationClass="com.intellij.codeInspection.sourceToSink.JavaSourceToSinkProvider"/>
|
||||||
<suppressionAnnotationUtil language="JAVA" implementationClass="com.intellij.codeInspection.JavaSuppressionAnnotationUtil"/>
|
|
||||||
</extensions>
|
</extensions>
|
||||||
<actions>
|
<actions>
|
||||||
<group id="UastInternal" text="UAST" internal="true" popup="true">
|
<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.modcommand.PsiUpdateModCommandQuickFix
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
import com.intellij.psi.PsiAnnotation
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiElementVisitor
|
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 com.intellij.uast.UastHintedVisitorAdapter
|
||||||
import org.jetbrains.annotations.VisibleForTesting
|
import org.jetbrains.annotations.VisibleForTesting
|
||||||
import org.jetbrains.uast.*
|
import org.jetbrains.uast.*
|
||||||
import org.jetbrains.uast.expressions.UInjectionHost
|
import org.jetbrains.uast.expressions.UInjectionHost
|
||||||
import org.jetbrains.uast.visitor.AbstractUastNonRecursiveVisitor
|
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
|
@VisibleForTesting
|
||||||
class SuppressionAnnotationInspection : AbstractBaseUastLocalInspectionTool() {
|
class SuppressionAnnotationInspection : AbstractBaseUastLocalInspectionTool() {
|
||||||
var myAllowedSuppressions: MutableList<String> = ArrayList()
|
var myAllowedSuppressions: MutableList<String> = ArrayList()
|
||||||
@@ -51,7 +54,6 @@ class SuppressionAnnotationInspection : AbstractBaseUastLocalInspectionTool() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inner class SuppressionAnnotationVisitor(private val holder: ProblemsHolder) : AbstractUastNonRecursiveVisitor() {
|
private inner class SuppressionAnnotationVisitor(private val holder: ProblemsHolder) : AbstractUastNonRecursiveVisitor() {
|
||||||
|
|
||||||
override fun visitElement(node: UElement): Boolean {
|
override fun visitElement(node: UElement): Boolean {
|
||||||
if (node is UComment) {
|
if (node is UComment) {
|
||||||
return visitComment(node)
|
return visitComment(node)
|
||||||
@@ -96,13 +98,12 @@ class SuppressionAnnotationInspection : AbstractBaseUastLocalInspectionTool() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitAnnotation(node: UAnnotation): Boolean {
|
override fun visitAnnotation(node: UAnnotation): Boolean {
|
||||||
val suppressionAnnotationUtil = SuppressionAnnotationUtil.extension.forLanguage(node.lang) ?: return false
|
val suppressDescriptor = node.suppressDescriptor()
|
||||||
if (suppressionAnnotationUtil.isSuppressionAnnotation(node)) {
|
if (suppressDescriptor == null) return true
|
||||||
val ids = getInspectionIdsSuppressedInAnnotation(node, suppressionAnnotationUtil)
|
val suppressIds = node.suppressIds(suppressDescriptor.attributeValue)
|
||||||
when {
|
when {
|
||||||
ids.isNotEmpty() && !myAllowedSuppressions.containsAll(ids) -> registerProblem(node, true)
|
suppressIds.isNotEmpty() && !myAllowedSuppressions.containsAll(suppressIds) -> registerProblem(node, true)
|
||||||
ids.isEmpty() -> registerProblem(node, false)
|
suppressIds.isEmpty() -> registerProblem(node, false)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -151,8 +152,8 @@ class SuppressionAnnotationInspection : AbstractBaseUastLocalInspectionTool() {
|
|||||||
private fun getIds(psiElement: PsiElement): Collection<String>? {
|
private fun getIds(psiElement: PsiElement): Collection<String>? {
|
||||||
val annotation = psiElement.toUElement()?.getParentOfType<UAnnotation>(strict = false)
|
val annotation = psiElement.toUElement()?.getParentOfType<UAnnotation>(strict = false)
|
||||||
if (annotation != null) {
|
if (annotation != null) {
|
||||||
val suppressionAnnotationUtil = SuppressionAnnotationUtil.extension.forLanguage(annotation.lang) ?: return null
|
val attributeValue = annotation.suppressDescriptor()?.attributeValue ?: return null
|
||||||
return getInspectionIdsSuppressedInAnnotation(annotation, suppressionAnnotationUtil)
|
return annotation.suppressIds(attributeValue)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val comment = psiElement.toUElement(UComment::class.java) ?: return null
|
val comment = psiElement.toUElement(UComment::class.java) ?: return null
|
||||||
@@ -170,29 +171,16 @@ class SuppressionAnnotationInspection : AbstractBaseUastLocalInspectionTool() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getInspectionIdsSuppressedInAnnotation(annotation: UAnnotation,
|
private fun UAnnotation.suppressDescriptor(): SuppressAnnotationDescriptor? {
|
||||||
suppressionAnnotationUtil: SuppressionAnnotationUtil): List<String> {
|
val shortName = uastAnchor?.name ?: return null
|
||||||
val sourcePsi = annotation.sourcePsi ?: return emptyList()
|
if (suppressAnnotations.none { descr -> descr.shortName == shortName }) return null
|
||||||
return CachedValuesManager.getCachedValue(sourcePsi) {
|
return suppressAnnotations.firstOrNull { descr -> "${descr.pkg}.${descr.shortName}" == qualifiedName }
|
||||||
CachedValueProvider.Result.create(
|
|
||||||
doGetInspectionIdsSuppressedInAnnotation(annotation, suppressionAnnotationUtil),
|
|
||||||
PsiModificationTracker.MODIFICATION_COUNT
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// do not move it into visitor class, as it will cause CachedValue-related exceptions
|
private fun UAnnotation.suppressIds(attributeName: String): List<String> = flattenedAttributeValues(attributeName).mapNotNull {
|
||||||
private fun doGetInspectionIdsSuppressedInAnnotation(annotation: UAnnotation,
|
when (it) {
|
||||||
suppressionAnnotationUtil: SuppressionAnnotationUtil): List<String> {
|
is UInjectionHost, is UReferenceExpression -> it.evaluateString()
|
||||||
val expressions = suppressionAnnotationUtil.getSuppressionAnnotationAttributeExpressions(annotation)
|
else -> null
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,18 +193,4 @@ private fun getIdsFromComment(commentText: String): List<String>? {
|
|||||||
else {
|
else {
|
||||||
return null
|
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")
|
""".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`() {
|
fun `test quickfix - allow multiple suppressions from annotation when array form used`() {
|
||||||
testAllowSuppressionQuickFix(JvmLanguage.JAVA, """
|
testAllowSuppressionQuickFix(JvmLanguage.JAVA, """
|
||||||
public class A {
|
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"/>
|
<documentationProvider implementation="org.jetbrains.kotlin.idea.KotlinDocumentationProvider"/>
|
||||||
|
|
||||||
<definitionsScopedSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDefinitionsSearcher"/>
|
<definitionsScopedSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDefinitionsSearcher"/>
|
||||||
|
|
||||||
<codeInspection.suppressionAnnotationUtil
|
|
||||||
language="kotlin"
|
|
||||||
implementationClass="org.jetbrains.kotlin.idea.inspections.KotlinSuppressionAnnotationUtil"/>
|
|
||||||
|
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user