[kotlin] K2: implement inspection suppression

A large part of functionality is made common from K1 implementation or ported to Analysis API.

^KTIJ-23786 Fixed

GitOrigin-RevId: 2c5a250073bb571cbde6b9ebc61d84bed35ccaad
This commit is contained in:
Artem Vasilev
2023-02-27 18:03:31 +01:00
committed by intellij-monorepo-bot
parent f875ce8e4b
commit f7f82026d0
12 changed files with 209 additions and 133 deletions

View File

@@ -1 +1,19 @@
highlighter.tool.tip.text.run.test=Run Test
highlighter.tool.tip.text.run.test=Run Test
intention.suppress.family=Suppress warnings
intention.suppress.text=Suppress ''{0}'' for {1} {2}
declaration.kind.statement=statement
declaration.kind.initializer=initializer
declaration.kind.object=object
declaration.kind.companion.object=companion object
declaration.kind.file=file
declaration.kind.secondary.constructor.of=secondary constructor of
declaration.kind.enum.entry=enum entry
declaration.kind.type.parameter=type parameter
declaration.kind.class=class
declaration.kind.interface=interface
declaration.kind.fun=fun
declaration.kind.val=val
declaration.kind.var=var
declaration.kind.parameter=parameter
declaration.name.0.of.1={0} of {1}
declaration.name.anonymous=<anonymous>

View File

@@ -0,0 +1,18 @@
// 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.suppress
import com.intellij.codeInsight.intention.FileModifier.SafeTypeForPreview
import com.intellij.openapi.util.NlsSafe
import org.jetbrains.annotations.Nls
@SafeTypeForPreview
class AnnotationHostKind(
/** Human-readable `KtElement` kind on which the annotation is placed. E.g., 'file', 'class' or 'statement'. */
@Nls val kind: String,
/** Name of the annotation owner. Might be null if the owner is not a named declaration (for instance, if it is a statement). */
@NlsSafe val name: String?,
/** True if the annotation needs to be added to a separate line. */
val newLineNeeded: Boolean
)

View File

@@ -1,6 +1,6 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// 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
package org.jetbrains.kotlin.idea.inspections.suppress
import com.intellij.codeInsight.daemon.QuickFixBundle
import com.intellij.codeInspection.*
@@ -10,13 +10,10 @@ import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiElement
import com.intellij.psi.util.isAncestor
import com.intellij.psi.util.parentOfType
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.idea.base.psi.KotlinPsiHeuristics
import org.jetbrains.kotlin.idea.base.psi.findSingleLiteralStringTemplateText
import org.jetbrains.kotlin.idea.base.psi.textRangeIn
import org.jetbrains.kotlin.idea.highlighter.createSuppressWarningActions
import org.jetbrains.kotlin.idea.util.findSingleLiteralStringTemplateText
import org.jetbrains.kotlin.psi.KtAnnotated
import org.jetbrains.kotlin.psi.KtAnnotatedExpression
import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments
@@ -41,9 +38,8 @@ class KotlinInspectionSuppressor : InspectionSuppressor, RedundantSuppressionDet
}.toTypedArray()
}
override fun isSuppressedFor(element: PsiElement, toolId: String): Boolean = KotlinCacheService.getInstance(element.project)
.getSuppressionCache()
.isSuppressed(element, element.containingFile, toolId, Severity.WARNING)
override fun isSuppressedFor(element: PsiElement, toolId: String): Boolean =
KotlinSuppressionChecker.getInstance().isSuppressedFor(element, toolId)
override fun getSuppressionIds(element: PsiElement): String? = suppressionIds(element).ifNotEmpty { joinToString(separator = ",") }

View File

@@ -1,7 +1,7 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.quickfix
// 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.suppress
import com.intellij.codeInsight.intention.FileModifier.SafeFieldForPreview
import com.intellij.codeInsight.intention.FileModifier
import com.intellij.codeInspection.SuppressIntentionAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
@@ -9,78 +9,77 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.idea.base.fe10.codeInsight.KotlinBaseFe10CodeInsightBundle
import org.jetbrains.kotlin.idea.base.fe10.highlighting.KotlinBaseFe10HighlightingBundle
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.highlighter.AnnotationHostKind
import org.jetbrains.kotlin.idea.base.codeInsight.KotlinBaseCodeInsightBundle
import org.jetbrains.kotlin.idea.util.addAnnotation
import org.jetbrains.kotlin.idea.util.findAnnotation
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
import org.jetbrains.kotlin.psi.psiUtil.replaceFileAnnotationList
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class KotlinSuppressIntentionAction(
suppressAt: KtElement,
private val suppressionKey: String,
@SafeFieldForPreview private val kind: AnnotationHostKind
suppressAt: KtElement,
private val suppressionKey: String,
@FileModifier.SafeFieldForPreview private val kind: AnnotationHostKind
) : SuppressIntentionAction() {
private val pointer = suppressAt.createSmartPointer()
@SafeFieldForPreview
@FileModifier.SafeFieldForPreview
private val project = suppressAt.project
override fun getFamilyName() = KotlinBaseFe10CodeInsightBundle.message("intention.suppress.family")
override fun getText() = KotlinBaseFe10CodeInsightBundle.message("intention.suppress.text", suppressionKey, kind.kind, kind.name ?: "")
private val suppressionKeyString = "\"$suppressionKey\""
override fun getFamilyName() = KotlinBaseCodeInsightBundle.message("intention.suppress.family")
override fun getText() = KotlinBaseCodeInsightBundle.message("intention.suppress.text", suppressionKey, kind.kind, kind.name ?: "")
override fun isAvailable(project: Project, editor: Editor?, element: PsiElement): Boolean {
if (isLambdaParameter(element)) {
// Lambda parameters can't be annotated: KT-13900
return false
}
return element.isValid
}
private fun isLambdaParameter(element: PsiElement): Boolean {
if (kind.kind != KotlinBaseFe10HighlightingBundle.message("declaration.kind.parameter")) return false
val parentParameter = element.parent.safeAs<KtParameter>()
?: element.parent.safeAs<KtDestructuringDeclarationEntry>()?.parent?.parent.safeAs<KtParameter>()
if (kind.kind != KotlinBaseCodeInsightBundle.message("declaration.kind.parameter")) return false
val parentParameter = element.parent as? KtParameter
?: (element.parent as? KtDestructuringDeclarationEntry)?.parent?.parent as? KtParameter
return parentParameter?.isLambdaParameter == true
}
override fun invoke(project: Project, editor: Editor?, element: PsiElement) {
if (!element.isValid) return
val suppressAt = pointer.element ?: return
val id = "\"$suppressionKey\""
when (suppressAt) {
is KtModifierListOwner -> suppressAt.addAnnotation(
StandardNames.FqNames.suppress,
id,
StandardClassIds.Annotations.Suppress,
suppressionKeyString,
whiteSpaceText = if (kind.newLineNeeded) "\n" else " ",
addToExistingAnnotation = { entry ->
addArgumentToSuppressAnnotation(
entry,
id
suppressionKeyString
); true
})
is KtAnnotatedExpression ->
suppressAtAnnotatedExpression(CaretBox(suppressAt, editor), id)
suppressAtAnnotatedExpression(CaretBox(suppressAt, editor), suppressionKeyString)
is KtExpression ->
suppressAtExpression(CaretBox(suppressAt, editor), id)
suppressAtExpression(CaretBox(suppressAt, editor), suppressionKeyString)
is KtFile ->
suppressAtFile(suppressAt, id)
suppressAtFile(suppressAt, suppressionKeyString)
}
}
override fun getFileModifierForPreview(target: PsiFile): KotlinSuppressIntentionAction {
return KotlinSuppressIntentionAction(
PsiTreeUtil.findSameElementInCopy(pointer.element, target),
suppressionKey,
kind
PsiTreeUtil.findSameElementInCopy(pointer.element, target),
suppressionKey,
kind
)
}
@@ -91,12 +90,13 @@ class KotlinSuppressIntentionAction(
if (fileAnnotationList == null) {
val newAnnotationList = psiFactory.createFileAnnotationListWithAnnotation(suppressAnnotationText(id, false))
val packageDirective = ktFile.packageDirective
val createAnnotationList = if (packageDirective != null && PsiTreeUtil.skipWhitespacesForward(packageDirective) == ktFile.importList) {
// packageDirective could be empty but suppression still should be added before it to generate consistent PSI
ktFile.addBefore(newAnnotationList, packageDirective) as KtFileAnnotationList
} else {
replaceFileAnnotationList(ktFile, newAnnotationList)
}
val createAnnotationList =
if (packageDirective != null && PsiTreeUtil.skipWhitespacesForward(packageDirective) == ktFile.importList) {
// packageDirective could be empty but suppression still should be added before it to generate consistent PSI
ktFile.addBefore(newAnnotationList, packageDirective) as KtFileAnnotationList
} else {
replaceFileAnnotationList(ktFile, newAnnotationList)
}
ktFile.addAfter(psiFactory.createWhiteSpace(kind), createAnnotationList)
return
@@ -107,7 +107,6 @@ class KotlinSuppressIntentionAction(
val newSuppressAnnotation = psiFactory.createFileAnnotation(suppressAnnotationText(id, false))
fileAnnotationList.add(psiFactory.createWhiteSpace(kind))
fileAnnotationList.add(newSuppressAnnotation) as KtAnnotationEntry
return
}
@@ -149,8 +148,10 @@ class KotlinSuppressIntentionAction(
when {
args == null -> // new argument list
entry.addAfter(newArgList, entry.lastChild)
args.arguments.isEmpty() -> // replace '()' with a new argument list
args.replace(newArgList)
else -> args.addArgument(newArgList.arguments[0])
}
}
@@ -160,19 +161,11 @@ class KotlinSuppressIntentionAction(
}
private fun findSuppressAnnotation(annotated: KtAnnotated): KtAnnotationEntry? {
val context = annotated.analyze()
return findSuppressAnnotation(context, annotated.annotationEntries)
return annotated.findAnnotation(StandardClassIds.Annotations.Suppress)
}
private fun findSuppressAnnotation(annotationList: KtFileAnnotationList): KtAnnotationEntry? {
val context = annotationList.analyze()
return findSuppressAnnotation(context, annotationList.annotationEntries)
}
private fun findSuppressAnnotation(context: BindingContext, annotationEntries: List<KtAnnotationEntry>): KtAnnotationEntry? {
return annotationEntries.firstOrNull { entry ->
context.get(BindingContext.ANNOTATION, entry)?.fqName == StandardNames.FqNames.suppress
}
return annotationList.findAnnotation(StandardClassIds.Annotations.Suppress)
}
}

View File

@@ -1,36 +1,28 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// 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.highlighter
package org.jetbrains.kotlin.idea.inspections.suppress
import com.intellij.codeInspection.SuppressIntentionAction
import com.intellij.codeInspection.SuppressableProblemGroup
import com.intellij.openapi.util.NlsSafe
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.idea.base.fe10.highlighting.KotlinBaseFe10HighlightingBundle
import org.jetbrains.kotlin.idea.base.codeInsight.KotlinBaseCodeInsightBundle
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
class KotlinSuppressableWarningProblemGroup(private val diagnosticFactory: DiagnosticFactory<*>) : SuppressableProblemGroup {
init {
assert(diagnosticFactory.severity == Severity.WARNING)
}
override fun getProblemName() = diagnosticFactory.name
class KotlinSuppressableWarningProblemGroup(private val factoryName: String) : SuppressableProblemGroup {
override fun getProblemName() = factoryName
override fun getSuppressActions(element: PsiElement?): Array<SuppressIntentionAction> {
return if (element != null) {
createSuppressWarningActions(element, diagnosticFactory).toTypedArray()
createSuppressWarningActions(element, Severity.WARNING, factoryName).toTypedArray()
} else {
SuppressIntentionAction.EMPTY_ARRAY
}
}
}
fun createSuppressWarningActions(element: PsiElement, diagnosticFactory: DiagnosticFactory<*>): List<SuppressIntentionAction> =
createSuppressWarningActions(element, diagnosticFactory.severity, diagnosticFactory.name)
fun createSuppressWarningActions(element: PsiElement, severity: Severity, suppressionKey: String): List<SuppressIntentionAction> {
if (severity != Severity.WARNING) {
return emptyList()
@@ -39,14 +31,13 @@ fun createSuppressWarningActions(element: PsiElement, severity: Severity, suppre
val actions = arrayListOf<SuppressIntentionAction>()
var current: PsiElement? = element
var suppressAtStatementAllowed = true
while (current != null) {
when {
current is KtDeclaration && current !is KtDestructuringDeclaration -> {
val declaration = current
val kind = DeclarationKindDetector.detect(declaration)
if (kind != null) {
actions.add(Fe10QuickFixProvider.getInstance(declaration.project).createSuppressFix(declaration, suppressionKey, kind))
if (kind != null ) {
actions.add(KotlinSuppressIntentionAction(declaration, suppressionKey, kind))
}
suppressAtStatementAllowed = false
}
@@ -55,19 +46,19 @@ fun createSuppressWarningActions(element: PsiElement, severity: Severity, suppre
// Add suppress action at first statement
if (current.parent is KtBlockExpression || current.parent is KtDestructuringDeclaration) {
val kind = if (current.parent is KtBlockExpression)
KotlinBaseFe10HighlightingBundle.message("declaration.kind.statement")
KotlinBaseCodeInsightBundle.message("declaration.kind.statement")
else
KotlinBaseFe10HighlightingBundle.message("declaration.kind.initializer")
KotlinBaseCodeInsightBundle.message("declaration.kind.initializer")
val hostKind = AnnotationHostKind(kind, null, true)
actions.add(Fe10QuickFixProvider.getInstance(current.project).createSuppressFix(current, suppressionKey, hostKind))
actions.add(KotlinSuppressIntentionAction(current, suppressionKey, hostKind))
suppressAtStatementAllowed = false
}
}
current is KtFile -> {
val hostKind = AnnotationHostKind(KotlinBaseFe10HighlightingBundle.message("declaration.kind.file"), current.name, true)
actions.add(Fe10QuickFixProvider.getInstance(current.project).createSuppressFix(current, suppressionKey, hostKind))
val hostKind = AnnotationHostKind(KotlinBaseCodeInsightBundle.message("declaration.kind.file"), current.name, true)
actions.add(KotlinSuppressIntentionAction(current, suppressionKey, hostKind))
suppressAtStatementAllowed = false
}
}
@@ -84,64 +75,55 @@ private object DeclarationKindDetector : KtVisitor<AnnotationHostKind?, Unit?>()
override fun visitDeclaration(declaration: KtDeclaration, data: Unit?) = null
private fun getDeclarationName(declaration: KtDeclaration): @NlsSafe String {
return declaration.name ?: KotlinBaseFe10HighlightingBundle.message("declaration.name.anonymous")
return declaration.name ?: KotlinBaseCodeInsightBundle.message("declaration.name.anonymous")
}
override fun visitClass(declaration: KtClass, data: Unit?): AnnotationHostKind {
val kind = when {
declaration.isInterface() -> KotlinBaseFe10HighlightingBundle.message("declaration.kind.interface")
else -> KotlinBaseFe10HighlightingBundle.message("declaration.kind.class")
declaration.isInterface() -> KotlinBaseCodeInsightBundle.message("declaration.kind.interface")
else -> KotlinBaseCodeInsightBundle.message("declaration.kind.class")
}
return AnnotationHostKind(kind, getDeclarationName(declaration), newLineNeeded = true)
}
override fun visitNamedFunction(declaration: KtNamedFunction, data: Unit?): AnnotationHostKind {
val kind = KotlinBaseFe10HighlightingBundle.message("declaration.kind.fun")
val kind = KotlinBaseCodeInsightBundle.message("declaration.kind.fun")
return AnnotationHostKind(kind, getDeclarationName(declaration), newLineNeeded = true)
}
override fun visitProperty(declaration: KtProperty, data: Unit?): AnnotationHostKind {
val kind = when {
declaration.isVar -> KotlinBaseFe10HighlightingBundle.message("declaration.kind.var")
else -> KotlinBaseFe10HighlightingBundle.message("declaration.kind.val")
declaration.isVar -> KotlinBaseCodeInsightBundle.message("declaration.kind.var")
else -> KotlinBaseCodeInsightBundle.message("declaration.kind.val")
}
return AnnotationHostKind(kind, getDeclarationName(declaration), newLineNeeded = true)
}
override fun visitDestructuringDeclaration(declaration: KtDestructuringDeclaration, data: Unit?): AnnotationHostKind {
val kind = when {
declaration.isVar -> KotlinBaseFe10HighlightingBundle.message("declaration.kind.var")
else -> KotlinBaseFe10HighlightingBundle.message("declaration.kind.val")
}
val name = declaration.entries.joinToString(", ", "(", ")") { it.name!! }
return AnnotationHostKind(kind, name, newLineNeeded = true)
}
override fun visitTypeParameter(declaration: KtTypeParameter, data: Unit?): AnnotationHostKind {
val kind = KotlinBaseFe10HighlightingBundle.message("declaration.kind.type.parameter")
val kind = KotlinBaseCodeInsightBundle.message("declaration.kind.type.parameter")
return AnnotationHostKind(kind, getDeclarationName(declaration), newLineNeeded = false)
}
override fun visitEnumEntry(declaration: KtEnumEntry, data: Unit?): AnnotationHostKind {
val kind = KotlinBaseFe10HighlightingBundle.message("declaration.kind.enum.entry")
val kind = KotlinBaseCodeInsightBundle.message("declaration.kind.enum.entry")
return AnnotationHostKind(kind, getDeclarationName(declaration), newLineNeeded = true)
}
override fun visitParameter(declaration: KtParameter, data: Unit?): AnnotationHostKind {
val kind = KotlinBaseFe10HighlightingBundle.message("declaration.kind.parameter")
val kind = KotlinBaseCodeInsightBundle.message("declaration.kind.parameter")
return AnnotationHostKind(kind, getDeclarationName(declaration), newLineNeeded = false)
}
override fun visitSecondaryConstructor(declaration: KtSecondaryConstructor, data: Unit?): AnnotationHostKind {
val kind = KotlinBaseFe10HighlightingBundle.message("declaration.kind.secondary.constructor.of")
val kind = KotlinBaseCodeInsightBundle.message("declaration.kind.secondary.constructor.of")
return AnnotationHostKind(kind, getDeclarationName(declaration), newLineNeeded = true)
}
override fun visitObjectDeclaration(d: KtObjectDeclaration, data: Unit?): AnnotationHostKind? {
return when {
d.isCompanion() -> {
val kind = KotlinBaseFe10HighlightingBundle.message("declaration.kind.companion.object")
val name = KotlinBaseFe10HighlightingBundle.message(
val kind = KotlinBaseCodeInsightBundle.message("declaration.kind.companion.object")
val name = KotlinBaseCodeInsightBundle.message(
"declaration.name.0.of.1",
d.name.toString(),
d.getStrictParentOfType<KtClass>()?.name.toString()
@@ -150,7 +132,7 @@ private object DeclarationKindDetector : KtVisitor<AnnotationHostKind?, Unit?>()
}
d.parent is KtObjectLiteralExpression -> null
else -> {
val kind = KotlinBaseFe10HighlightingBundle.message("declaration.kind.object")
val kind = KotlinBaseCodeInsightBundle.message("declaration.kind.object")
AnnotationHostKind(kind, getDeclarationName(d), newLineNeeded = true)
}
}

View File

@@ -0,0 +1,96 @@
// 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.util
import org.jetbrains.kotlin.analysis.api.analyze
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.idea.base.codeInsight.ShortenReferencesFacility
import org.jetbrains.kotlin.idea.base.psi.KotlinPsiHeuristics
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.renderer.render
/**
* Add a new annotation to the declaration or expression, or modify an existing annotation. Uses [analyze].
*
* Note: if the search for an existing annotation is enabled (this is default for compatibility), the function will
* resolve annotation names. This should be avoided if the function is called from an event dispatcher thread (EDT),
* e.g., if it is a part of a write action such as the `invoke()` function of a quick fix.
*
* @receiver the annotation owner to modify
* @param annotationClassId fully qualified name of the annotation to add
* @param annotationInnerText the inner text (rendered arguments) of the annotation, or null if there is no inner text (default)
* @param useSiteTarget the use site target of the annotation, or null if no explicit use site target is provided
* @param searchForExistingEntry `true` if the function should search for an existing annotation and update it instead of creating a new entry
* @param whiteSpaceText the whitespace separator that should be inserted between annotation entries (newline by default)
* @param addToExistingAnnotation a lambda expression to run on an existing annotation if it has been found
* @return `true` if an annotation has been added or modified, `false` otherwise
*/
fun KtModifierListOwner.addAnnotation(
annotationClassId: ClassId,
annotationInnerText: String? = null,
useSiteTarget: AnnotationUseSiteTarget? = null,
searchForExistingEntry: Boolean = true,
whiteSpaceText: String = "\n",
addToExistingAnnotation: ((KtAnnotationEntry) -> Boolean)? = null
): Boolean {
val annotationText = buildString {
append('@')
if (useSiteTarget != null) append("${useSiteTarget.renderName}:")
append(annotationClassId.asSingleFqName().render())
if (annotationInnerText != null) append("($annotationInnerText)")
}
val psiFactory = KtPsiFactory(project)
val modifierList = modifierList
if (modifierList == null) {
val addedAnnotation = addAnnotationEntry(psiFactory.createAnnotationEntry(annotationText))
ShortenReferencesFacility.getInstance().shorten(addedAnnotation)
return true
}
val entry = if (searchForExistingEntry) findAnnotation(annotationClassId, useSiteTarget) else null
if (entry == null) {
// no annotation
val newAnnotation = psiFactory.createAnnotationEntry(annotationText)
val addedAnnotation = modifierList.addBefore(newAnnotation, modifierList.firstChild) as KtElement
val whiteSpace = psiFactory.createWhiteSpace(whiteSpaceText)
modifierList.addAfter(whiteSpace, addedAnnotation)
ShortenReferencesFacility.getInstance().shorten(addedAnnotation)
return true
}
if (addToExistingAnnotation != null) {
return addToExistingAnnotation(entry)
}
return false
}
fun KtAnnotated.findAnnotation(
annotationClassId: ClassId,
useSiteTarget: AnnotationUseSiteTarget? = null,
withResolve: Boolean = false
): KtAnnotationEntry? {
val annotationEntry = KotlinPsiHeuristics.findAnnotation(this, annotationClassId.asSingleFqName(), useSiteTarget)
return annotationEntry?.takeIf { isAnnotationWithClassId(it, annotationClassId, withResolve) }
}
fun KtFileAnnotationList.findAnnotation(
annotationClassId: ClassId,
useSiteTarget: AnnotationUseSiteTarget? = null,
withResolve: Boolean = false
): KtAnnotationEntry? {
val annotationEntry = KotlinPsiHeuristics.findAnnotation(this, annotationClassId.asSingleFqName(), useSiteTarget)
return annotationEntry?.takeIf { isAnnotationWithClassId(it, annotationClassId, withResolve) }
}
private fun isAnnotationWithClassId(entry: KtAnnotationEntry, classId: ClassId, withResolve: Boolean): Boolean {
if (entry.shortName != classId.shortClassName) return false
if (!withResolve) return true
return analyze(entry) {
entry.typeReference?.getKtType()?.isClassTypeWithClassId(classId) == true
}
}

View File

@@ -10,11 +10,11 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.codeinsight.api.classic.quickfixes.UnresolvedReferenceQuickFixFactory
import org.jetbrains.kotlin.idea.highlighter.AnnotationHostKind
import org.jetbrains.kotlin.idea.highlighter.Fe10QuickFixProvider
import org.jetbrains.kotlin.idea.highlighter.RegisterQuickFixesLaterIntentionAction
import org.jetbrains.kotlin.idea.inspections.suppress.AnnotationHostKind
import org.jetbrains.kotlin.idea.inspections.suppress.KotlinSuppressIntentionAction
import org.jetbrains.kotlin.idea.quickfix.KotlinIntentionActionsFactory
import org.jetbrains.kotlin.idea.quickfix.KotlinSuppressIntentionAction
import org.jetbrains.kotlin.idea.quickfix.QuickFixes
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.types.KotlinType

View File

@@ -22,5 +22,6 @@
<orderEntry type="module" module-name="kotlin.base.fe10.analysis" />
<orderEntry type="module" module-name="intellij.platform.lang.impl" />
<orderEntry type="module" module-name="intellij.java.psi" />
<orderEntry type="module" module-name="kotlin.base.code-insight" />
</component>
</module>

View File

@@ -21,24 +21,6 @@ root.package=root package
function.receiver.0=receiver: {0}
function.arguments=arguments:\u0020
declaration.name.0.of.1={0} of {1}
declaration.name.anonymous=<anonymous>
declaration.kind.statement=statement
declaration.kind.initializer=initializer
declaration.kind.object=object
declaration.kind.companion.object=companion object
declaration.kind.file=file
declaration.kind.secondary.constructor.of=secondary constructor of
declaration.kind.enum.entry=enum entry
declaration.kind.type.parameter=type parameter
declaration.kind.class=class
declaration.kind.interface=interface
declaration.kind.fun=fun
declaration.kind.val=val
declaration.kind.var=var
declaration.kind.parameter=parameter
html.0.has.no.corresponding.expected.declaration.1.html={0} has no corresponding expected declaration{1}
html.0.is.not.abstract.and.does.not.implement.abstract.base.class.member.br.1.html={0} is not abstract and does not implement abstract base class member<br/>{1}
html.0.is.not.abstract.and.does.not.implement.abstract.member.br.1.html={0} is not abstract and does not implement abstract member<br/>{1}

View File

@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
import org.jetbrains.kotlin.idea.base.fe10.highlighting.KotlinBaseFe10HighlightingBundle
import org.jetbrains.kotlin.idea.inspections.suppress.KotlinSuppressableWarningProblemGroup
import org.jetbrains.kotlin.idea.util.application.isApplicationInternalMode
import org.jetbrains.kotlin.idea.util.application.isUnitTestMode
@@ -45,7 +46,7 @@ class AnnotationPresentationInfo(
for (range in ranges) {
for (diagnostic in diagnostics) {
val group = if (diagnostic.severity == Severity.WARNING) {
KotlinSuppressableWarningProblemGroup(diagnostic.factory)
KotlinSuppressableWarningProblemGroup(diagnostic.factory.name)
} else {
null
}

View File

@@ -6,11 +6,10 @@ import com.intellij.codeInspection.SuppressIntentionAction
import com.intellij.openapi.components.service
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.NlsSafe
import com.intellij.psi.PsiFile
import com.intellij.util.containers.MultiMap
import org.jetbrains.annotations.Nls
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.inspections.suppress.AnnotationHostKind
import org.jetbrains.kotlin.psi.KtElement
interface Fe10QuickFixProvider {
@@ -25,17 +24,6 @@ interface Fe10QuickFixProvider {
fun createSuppressFix(element: KtElement, suppressionKey: String, hostKind: AnnotationHostKind): SuppressIntentionAction
}
class AnnotationHostKind(
/** Human-readable `KtElement` kind on which the annotation is placed. E.g., 'file', 'class' or 'statement'. */
@Nls val kind: String,
/** Name of the annotation owner. Might be null if the owner is not a named declaration (for instance, if it is a statement). */
@NlsSafe val name: String?,
/** True if the annotation needs to be added to a separate line. */
val newLineNeeded: Boolean
)
object RegisterQuickFixesLaterIntentionAction : IntentionAction {
override fun getText(): String = ""

View File

@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.resolve.konan.diagnostics.ErrorsNative
import java.lang.reflect.Modifier
import org.jetbrains.kotlin.idea.codeinsight.api.classic.inspections.AbstractKotlinInspection
import org.jetbrains.kotlin.idea.inspections.suppress.KotlinInspectionSuppressor
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
class KotlinRedundantDiagnosticSuppressInspection : AbstractKotlinInspection() {