mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 03:21:12 +07:00
IDEA-337709: Reimplement SuppressionAnnotationInspection to UAST
GitOrigin-RevId: 5384975e4786fbc34114065e117f66d930435621
This commit is contained in:
committed by
intellij-monorepo-bot
parent
7ba6375831
commit
ad246cb491
@@ -246,8 +246,6 @@ cloneable.class.without.clone.todo.message=TODO: copy mutable state here, so the
|
||||
use.obsolete.collection.type.display.name=Use of obsolete collection type
|
||||
use.obsolete.collection.type.problem.descriptor=Obsolete collection type <code>#ref</code> used #loc
|
||||
use.obsolete.collection.type.ignore.library.arguments.option=Ignore obsolete collection types where they are required
|
||||
inspection.suppression.annotation.display.name=Inspection suppression annotation
|
||||
inspection.suppression.annotation.problem.descriptor=Inspection suppression annotation <code>#ref</code> #loc
|
||||
use.system.out.err.display.name=Use of 'System.out' or 'System.err'
|
||||
use.system.out.err.problem.descriptor=Uses of <code>#ref</code> should probably be replaced with more robust logging #loc
|
||||
dumpstack.call.display.name=Call to 'Thread.dumpStack()'
|
||||
@@ -2468,10 +2466,6 @@ fix.data.provider.signature.family.name=Fix data provider method signature
|
||||
fix.data.provider.signature.missing.method.problem=Parameterized test class <code>#ref</code> lacks data provider method annotated with '@Parameters'
|
||||
fix.data.provider.signature.incorrect.problem=Data provider method <code>#ref()</code> has an incorrect signature
|
||||
fix.data.provider.multiple.methods.problem=Multiple @Parameters data provider methods present in class <code>#ref</code>
|
||||
allow.suppressions.fix.family.name=Allow suppressions
|
||||
allow.suppressions.fix.text=Allow these suppressions
|
||||
allow.suppressions.preview.text=Inspection id will be added to the list of allowed suppressions in settings
|
||||
remove.suppress.comment.fix.family.name=Remove //{0}
|
||||
throws.runtime.exception.fix.family.name=Remove from 'throws' clause
|
||||
move.exception.to.javadoc.fix.family.name=Move to Javadoc '@throws'
|
||||
create.package.info.java.family.name=Create 'package-info.java'
|
||||
|
||||
@@ -1437,10 +1437,6 @@
|
||||
implementationClass="com.siyeh.ig.logging.StringConcatenationArgumentToLogCallInspection" cleanupTool="true"/>
|
||||
|
||||
<!--group.names.code.maturity.issues-->
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="SuppressionAnnotation" bundle="messages.InspectionGadgetsBundle"
|
||||
key="inspection.suppression.annotation.display.name" groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.code.maturity.issues" enabledByDefault="false" level="WARNING"
|
||||
implementationClass="com.siyeh.ig.maturity.SuppressionAnnotationInspection"/>
|
||||
<localInspection groupPath="Java" language="JAVA" suppressId="UseOfSystemOutOrSystemErr" shortName="SystemOutErr" bundle="messages.InspectionGadgetsBundle"
|
||||
key="use.system.out.err.display.name" groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.code.maturity.issues" enabledByDefault="false" level="WARNING"
|
||||
|
||||
@@ -1,178 +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.siyeh.ig.maturity;
|
||||
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.codeInspection.options.OptPane;
|
||||
import com.intellij.java.JavaBundle;
|
||||
import com.intellij.modcommand.ModCommand;
|
||||
import com.intellij.modcommand.ModCommandQuickFix;
|
||||
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.*;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.codeInspection.options.OptPane.pane;
|
||||
|
||||
public class SuppressionAnnotationInspection extends BaseInspection {
|
||||
public List<String> myAllowedSuppressions = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public @NotNull OptPane getOptionsPane() {
|
||||
return pane(OptPane.stringList("myAllowedSuppressions", JavaBundle.message("ignored.suppressions")));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LocalQuickFix @NotNull [] buildFixes(Object... infos) {
|
||||
final boolean suppressionIdPresent = ((Boolean)infos[1]).booleanValue();
|
||||
if (infos[0] instanceof PsiAnnotation annotation) {
|
||||
return suppressionIdPresent
|
||||
? new LocalQuickFix[]{new RemoveAnnotationQuickFix(annotation, null), new AllowSuppressionsFix()}
|
||||
: new LocalQuickFix[]{new RemoveAnnotationQuickFix(annotation, null),};
|
||||
} else if (infos[0] instanceof PsiComment) {
|
||||
return suppressionIdPresent
|
||||
? new LocalQuickFix[]{new RemoveSuppressCommentFix(), new AllowSuppressionsFix()}
|
||||
: new LocalQuickFix[]{new RemoveSuppressCommentFix()};
|
||||
}
|
||||
return InspectionGadgetsFix.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"inspection.suppression.annotation.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuppressedFor(@NotNull PsiElement element) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuppressQuickFix @NotNull [] getBatchSuppressActions(@Nullable PsiElement element) {
|
||||
return SuppressQuickFix.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new SuppressionAnnotationVisitor();
|
||||
}
|
||||
|
||||
private static class RemoveSuppressCommentFix extends PsiUpdateModCommandQuickFix {
|
||||
@Override
|
||||
protected void applyFix(@NotNull Project project, @NotNull PsiElement startElement, @NotNull ModPsiUpdater updater) {
|
||||
startElement.delete();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return InspectionGadgetsBundle.message("remove.suppress.comment.fix.family.name", SuppressionUtilCore.SUPPRESS_INSPECTIONS_TAG_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
private class AllowSuppressionsFix extends ModCommandQuickFix {
|
||||
@Override
|
||||
public @NotNull ModCommand perform(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
final PsiElement psiElement = descriptor.getPsiElement();
|
||||
final Iterable<String> ids;
|
||||
if (psiElement instanceof PsiAnnotation) {
|
||||
ids = JavaSuppressionUtil.getInspectionIdsSuppressedInAnnotation((PsiModifierList)psiElement.getParent());
|
||||
}
|
||||
else {
|
||||
final String suppressedIds = JavaSuppressionUtil.getSuppressedInspectionIdsIn(psiElement);
|
||||
if (suppressedIds == null) {
|
||||
return ModCommand.nop();
|
||||
}
|
||||
ids = StringUtil.tokenize(suppressedIds, ",");
|
||||
}
|
||||
return ModCommand.updateInspectionOption(psiElement, SuppressionAnnotationInspection.this, inspection -> {
|
||||
for (String id : ids) {
|
||||
if (!inspection.myAllowedSuppressions.contains(id)) {
|
||||
inspection.myAllowedSuppressions.add(id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return InspectionGadgetsBundle.message("allow.suppressions.fix.text");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return InspectionGadgetsBundle.message("allow.suppressions.fix.family.name");
|
||||
}
|
||||
}
|
||||
|
||||
private class SuppressionAnnotationVisitor extends BaseInspectionVisitor {
|
||||
@Override
|
||||
public void visitComment(@NotNull PsiComment comment) {
|
||||
super.visitComment(comment);
|
||||
final IElementType tokenType = comment.getTokenType();
|
||||
if (!tokenType.equals(JavaTokenType.END_OF_LINE_COMMENT)
|
||||
&& !tokenType.equals(JavaTokenType.C_STYLE_COMMENT)) {
|
||||
return;
|
||||
}
|
||||
final String commentText = comment.getText();
|
||||
if (commentText.length() <= 2) {
|
||||
return;
|
||||
}
|
||||
@NonNls final String strippedComment = commentText.substring(2).trim();
|
||||
if (!strippedComment.startsWith(SuppressionUtilCore.SUPPRESS_INSPECTIONS_TAG_NAME)) {
|
||||
return;
|
||||
}
|
||||
final String suppressedIds = JavaSuppressionUtil.getSuppressedInspectionIdsIn(comment);
|
||||
if (suppressedIds == null) {
|
||||
registerError(comment, comment, Boolean.FALSE);
|
||||
return;
|
||||
}
|
||||
final Iterable<String> ids = StringUtil.tokenize(suppressedIds, ",");
|
||||
for (String id : ids) {
|
||||
if (!myAllowedSuppressions.contains(id)) {
|
||||
registerError(comment, comment, Boolean.TRUE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAnnotation(@NotNull PsiAnnotation annotation) {
|
||||
super.visitAnnotation(annotation);
|
||||
final PsiJavaCodeReferenceElement reference = annotation.getNameReferenceElement();
|
||||
if (reference == null) {
|
||||
return;
|
||||
}
|
||||
@NonNls final String text = reference.getText();
|
||||
if ("SuppressWarnings".equals(text) ||
|
||||
BatchSuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME.equals(text)) {
|
||||
final PsiElement annotationParent = annotation.getParent();
|
||||
if (annotationParent instanceof PsiModifierList) {
|
||||
final Collection<String> ids = JavaSuppressionUtil.getInspectionIdsSuppressedInAnnotation((PsiModifierList)annotationParent);
|
||||
if (!myAllowedSuppressions.containsAll(ids)) {
|
||||
registerError(annotation, annotation, Boolean.TRUE);
|
||||
}
|
||||
else if (ids.isEmpty()) {
|
||||
registerError(annotation, annotation, Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<warning descr="Inspection suppression annotation '@SuppressWarnings({\\"ALL\\", \\"SuppressionAnnotation\\"})'">@SuppressWarnings({"ALL", "SuppressionAnnotation"})</warning>
|
||||
public class SuppressionAnnotation {
|
||||
|
||||
<warning descr="Inspection suppression annotation '@SuppressWarnings(\\"PublicField\\")'">@SuppressWarnings("PublicField")</warning>
|
||||
public String s;
|
||||
|
||||
<warning descr="Inspection suppression annotation '@SuppressWarnings({})'">@SuppressWarnings({})</warning>
|
||||
public String t;
|
||||
|
||||
void foo() {
|
||||
<warning descr="Inspection suppression annotation '//noinspection HardCodedStringLiteral'">//noinspection HardCodedStringLiteral</warning>
|
||||
System.out.println("hello");
|
||||
<warning descr="Inspection suppression annotation '//noinspection'">//noinspection</warning>
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
@SuppressWarnings("FreeSpeech")
|
||||
void bar() {
|
||||
//noinspection FreeSpeech
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.siyeh.ig.maturity;
|
||||
|
||||
import com.intellij.codeInspection.InspectionProfileEntry;
|
||||
import com.siyeh.ig.LightJavaInspectionTestCase;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Bas Leijdekkers
|
||||
*/
|
||||
public class SuppressionAnnotationInspectionTest extends LightJavaInspectionTestCase {
|
||||
|
||||
public void testSuppressionAnnotation() { doTest(); }
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected InspectionProfileEntry getInspection() {
|
||||
final SuppressionAnnotationInspection inspection = new SuppressionAnnotationInspection();
|
||||
inspection.myAllowedSuppressions.add("FreeSpeech");
|
||||
return inspection;
|
||||
}
|
||||
}
|
||||
@@ -1679,7 +1679,6 @@ code.vision.overrides.hint={0, choice, 1#1 override|2#{0,number} overrides}
|
||||
hint.text.tostring.method.could.not.be.created.from.template=''toString()'' method could not be created from template ''{0}''
|
||||
hint.text.tostring.template.invalid=toString() template ''{0}'' is invalid
|
||||
command.name.generate.tostring=Generate toString()
|
||||
ignored.suppressions=Ignored suppressions:
|
||||
hint.text.removed.imports=Removed {0} {1, choice, 0#import|1#imports}
|
||||
hint.text.added.imports=, added {0} {1, choice, 0#import|1#imports}
|
||||
hint.text.rearranged.imports=Rearranged imports
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// 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.psi.PsiElement
|
||||
import org.jetbrains.uast.UAnnotation
|
||||
import org.jetbrains.uast.UExpression
|
||||
|
||||
private val EP_NAME: ExtensionPointName<SuppressionAnnotationUtil> =
|
||||
ExtensionPointName.create("com.intellij.codeInspection.suppressionAnnotationUtil")
|
||||
|
||||
interface SuppressionAnnotationUtil {
|
||||
companion object {
|
||||
@JvmField
|
||||
val extension = LanguageExtension<SuppressionAnnotationUtil>(EP_NAME.name)
|
||||
}
|
||||
|
||||
fun isSuppressionAnnotation(annotation: UAnnotation): Boolean
|
||||
fun getSuppressionAnnotationAttributeExpressions(annotation: UAnnotation): List<UExpression>
|
||||
fun getRemoveAnnotationQuickFix(annotation: PsiElement): LocalQuickFix?
|
||||
}
|
||||
@@ -9,7 +9,11 @@
|
||||
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-->
|
||||
@@ -203,6 +207,11 @@
|
||||
groupBundle="messages.JvmAnalysisBundle" bundle="messages.JvmAnalysisBundle"
|
||||
groupKey="jvm.inspections.group.name" key="jvm.inspections.system.get.property.display.name"
|
||||
implementationClass="com.intellij.codeInspection.SystemGetPropertyInspection"/>
|
||||
<localInspection language="UAST" enabledByDefault="false" level="WARNING"
|
||||
shortName="SuppressionAnnotation"
|
||||
groupBundle="messages.JvmAnalysisBundle" bundle="messages.JvmAnalysisBundle"
|
||||
groupKey="jvm.inspections.group.name" key="inspection.suppression.annotation.display.name"
|
||||
implementationClass="com.intellij.codeInspection.SuppressionAnnotationInspection"/>
|
||||
<notificationGroup id="UAST" displayType="BALLOON" hideFromSettings="true"/>
|
||||
<projectService serviceInterface="com.intellij.codeInsight.AnnotationCacheOwnerNormalizer"
|
||||
serviceImplementation="com.intellij.psi.UastAnnotationCacheOwnerNormalizer"/>
|
||||
@@ -214,6 +223,7 @@
|
||||
</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">
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
Reports comments or annotations suppressing inspections.
|
||||
<p>This inspection can be useful when leaving suppressions intentionally for further review.</p>
|
||||
<p><b>Example:</b></p>
|
||||
<pre><code>
|
||||
@SuppressWarnings("unused")
|
||||
static Stream<String> stringProvider() {
|
||||
return Stream.of("foo", "bar");
|
||||
}
|
||||
<pre><code lang="Java">
|
||||
@SuppressWarnings("unused")
|
||||
static Stream<String> stringProvider() {
|
||||
return Stream.of("foo", "bar");
|
||||
}
|
||||
</code></pre>
|
||||
<!-- tooltip end -->
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -300,3 +300,10 @@ title.uast=UAST
|
||||
current.version=Current version
|
||||
dialog.title.choose.annotation=Choose {0}
|
||||
jvm.inspections.dependency.intention.description=Opens a dialog to configure dependency rules between scopes.
|
||||
|
||||
inspection.suppression.annotation.display.name=Inspection suppression annotation
|
||||
inspection.suppression.annotation.problem.descriptor=Inspection suppression annotation <code>#ref</code> #loc
|
||||
ignored.suppressions=Ignored suppressions:
|
||||
remove.suppress.comment.fix.family.name=Remove //{0}
|
||||
allow.suppressions.fix.family.name=Allow suppressions
|
||||
allow.suppressions.fix.text=Allow these suppressions
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
// 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.analysis.JvmAnalysisBundle
|
||||
import com.intellij.codeInspection.options.OptPane
|
||||
import com.intellij.lang.jvm.JvmAnnotation
|
||||
import com.intellij.modcommand.ModCommand
|
||||
import com.intellij.modcommand.ModCommandQuickFix
|
||||
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.visitor.AbstractUastNonRecursiveVisitor
|
||||
import com.intellij.jvm.analysis.quickFix.RemoveAnnotationQuickFix as RemoveJvmAnnotationQuickFix
|
||||
|
||||
@VisibleForTesting
|
||||
class SuppressionAnnotationInspection : AbstractBaseUastLocalInspectionTool() {
|
||||
var myAllowedSuppressions: MutableList<String> = ArrayList()
|
||||
|
||||
override fun getOptionsPane(): OptPane {
|
||||
return OptPane.pane(OptPane.stringList("myAllowedSuppressions", JvmAnalysisBundle.message("ignored.suppressions")))
|
||||
}
|
||||
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
|
||||
return UastHintedVisitorAdapter.create(
|
||||
holder.file.language,
|
||||
SuppressionAnnotationVisitor(holder),
|
||||
arrayOf(UAnnotation::class.java, UComment::class.java),
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
override fun isSuppressedFor(element: PsiElement): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun getBatchSuppressActions(element: PsiElement?): Array<SuppressQuickFix> {
|
||||
return SuppressQuickFix.EMPTY_ARRAY
|
||||
}
|
||||
|
||||
private inner class SuppressionAnnotationVisitor(private val holder: ProblemsHolder) : AbstractUastNonRecursiveVisitor() {
|
||||
|
||||
override fun visitElement(node: UElement): Boolean {
|
||||
if (node is UComment) {
|
||||
return visitComment(node)
|
||||
}
|
||||
else {
|
||||
return super.visitElement(node)
|
||||
}
|
||||
}
|
||||
|
||||
private fun visitComment(comment: UComment): Boolean {
|
||||
if (isSuppressComment(comment)) {
|
||||
val ids = getIdsFromComment(comment.text)
|
||||
if (ids != null) {
|
||||
for (id in ids) {
|
||||
if (!myAllowedSuppressions.contains(id)) {
|
||||
registerProblem(comment, true)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
registerProblem(comment, false)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun isSuppressComment(comment: UComment): Boolean {
|
||||
val text = comment.text
|
||||
if (text.length <= 2 && !text.startsWith("//")) {
|
||||
return false
|
||||
}
|
||||
val strippedComment = text.substring(2).trim()
|
||||
return strippedComment.startsWith(SuppressionUtilCore.SUPPRESS_INSPECTIONS_TAG_NAME)
|
||||
}
|
||||
|
||||
private fun registerProblem(comment: UComment, addAllowSuppressionsFix: Boolean) {
|
||||
val fixes = if (addAllowSuppressionsFix) arrayOf(RemoveSuppressCommentFix(), AllowSuppressionsFix())
|
||||
else arrayOf(RemoveSuppressCommentFix())
|
||||
holder.registerProblem(comment.sourcePsi, JvmAnalysisBundle.message("inspection.suppression.annotation.problem.descriptor"), *fixes)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun registerProblem(annotation: UAnnotation, addAllowSuppressionsFix: Boolean) {
|
||||
val sourcePsi = annotation.sourcePsi ?: return
|
||||
var fixes: Array<LocalQuickFix> = if (addAllowSuppressionsFix) arrayOf(AllowSuppressionsFix()) else arrayOf()
|
||||
val removeAnnotationFix = getRemoveAnnotationFix(sourcePsi)
|
||||
if (removeAnnotationFix != null) {
|
||||
fixes += removeAnnotationFix
|
||||
}
|
||||
holder.registerProblem(sourcePsi, JvmAnalysisBundle.message("inspection.suppression.annotation.problem.descriptor"), *fixes)
|
||||
}
|
||||
|
||||
private fun getRemoveAnnotationFix(annotationElement: PsiElement): LocalQuickFix? {
|
||||
val suppressionAnnotationUtil = SuppressionAnnotationUtil.extension.forLanguage(annotationElement.language)
|
||||
val quickFix = suppressionAnnotationUtil?.getRemoveAnnotationQuickFix(annotationElement)
|
||||
if (quickFix != null) {
|
||||
return quickFix
|
||||
}
|
||||
val jvmAnnotation = annotationElement as? JvmAnnotation ?: return null
|
||||
return RemoveJvmAnnotationQuickFix(jvmAnnotation)
|
||||
}
|
||||
}
|
||||
|
||||
private class RemoveSuppressCommentFix : PsiUpdateModCommandQuickFix() {
|
||||
override fun applyFix(project: Project, startElement: PsiElement, updater: ModPsiUpdater) {
|
||||
startElement.delete()
|
||||
}
|
||||
|
||||
override fun getFamilyName(): String {
|
||||
return JvmAnalysisBundle.message("remove.suppress.comment.fix.family.name", SuppressionUtilCore.SUPPRESS_INSPECTIONS_TAG_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
private inner class AllowSuppressionsFix : ModCommandQuickFix() {
|
||||
override fun perform(project: Project, descriptor: ProblemDescriptor): ModCommand {
|
||||
val psiElement = descriptor.psiElement
|
||||
val ids = getIds(psiElement) ?: return ModCommand.nop()
|
||||
return ModCommand.updateOption(psiElement, this@SuppressionAnnotationInspection) { inspection ->
|
||||
for (id in ids) {
|
||||
if (!inspection.myAllowedSuppressions.contains(id)) {
|
||||
inspection.myAllowedSuppressions.add(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
else {
|
||||
val comment = psiElement.toUElement(UComment::class.java) ?: return null
|
||||
return getIdsFromComment(comment.text)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getName(): String {
|
||||
return JvmAnalysisBundle.message("allow.suppressions.fix.text")
|
||||
}
|
||||
|
||||
override fun getFamilyName(): String {
|
||||
return JvmAnalysisBundle.message("allow.suppressions.fix.family.name")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 ULiteralExpression -> listOfNotNull(expression.value as? String)
|
||||
is UReferenceExpression -> listOfNotNull(expression.evaluateString())
|
||||
is UCallExpression -> expression.valueArguments.flatMap { getInspectionIdsSuppressedInAnnotation(it) }
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getIdsFromComment(commentText: String): List<String>? {
|
||||
val matcher = SuppressionUtil.SUPPRESS_IN_LINE_COMMENT_PATTERN.matcher(commentText)
|
||||
if (matcher.matches()) {
|
||||
val suppressedIds = matcher.group(1).trim()
|
||||
return StringUtil.tokenize(suppressedIds, ",").toList().map { it.trim() }
|
||||
}
|
||||
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 }
|
||||
}
|
||||
|
||||
override fun getRemoveAnnotationQuickFix(annotation: PsiElement): LocalQuickFix? {
|
||||
return null // default will be used
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.intellij.jvm.analysis.internal.testFramework
|
||||
|
||||
import com.intellij.codeInspection.SuppressionAnnotationInspection
|
||||
import com.intellij.codeInspection.ex.InspectionProfileImpl
|
||||
import com.intellij.jvm.analysis.testFramework.JvmInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.profile.codeInspection.InspectionProfileManager
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
|
||||
abstract class SuppressionAnnotationInspectionTestBase : JvmInspectionTestBase() {
|
||||
|
||||
override val inspection = SuppressionAnnotationInspection()
|
||||
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = object : ProjectDescriptor(LanguageLevel.HIGHEST, true) {}
|
||||
|
||||
protected fun testAllowSuppressionQuickFix(jvmLanguage: JvmLanguage, code: String, vararg ids: String) {
|
||||
InspectionProfileImpl.INIT_INSPECTIONS = true
|
||||
try {
|
||||
assertEmpty(inspection.myAllowedSuppressions)
|
||||
myFixture.configureByText("A.${jvmLanguage.ext}", code)
|
||||
val intention = myFixture.findSingleIntention("Allow these suppressions")
|
||||
val previewText = buildPreviewText(ids)
|
||||
myFixture.checkIntentionPreviewHtml(
|
||||
intention,
|
||||
previewText
|
||||
)
|
||||
myFixture.launchAction(intention)
|
||||
val inspection = InspectionProfileManager.getInstance(project).currentProfile
|
||||
.getUnwrappedTool("SuppressionAnnotation", file) as SuppressionAnnotationInspection
|
||||
assertContainsElements(inspection.myAllowedSuppressions, ids.toList())
|
||||
}
|
||||
finally {
|
||||
InspectionProfileImpl.INIT_INSPECTIONS = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildPreviewText(ids: Array<out String>): String {
|
||||
val idsPart = ids.joinToString(separator = "") { "<option selected=\"selected\">$it</option>" }
|
||||
return "Ignored suppressions:<br/><br/><select multiple=\"multiple\" size=\"${ids.size + 2}\">$idsPart</select>"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package com.intellij.codeInspection.tests.java
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.SuppressionAnnotationInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
|
||||
class JavaSuppressionAnnotationInspectionTest : SuppressionAnnotationInspectionTestBase() {
|
||||
|
||||
fun `test highlighting`() {
|
||||
inspection.myAllowedSuppressions.add("FreeSpeech")
|
||||
myFixture.testHighlighting(
|
||||
JvmLanguage.JAVA,
|
||||
"""
|
||||
<warning descr="Inspection suppression annotation '@SuppressWarnings({\"ALL\", \"SuppressionAnnotation\"})'">@SuppressWarnings({"ALL", "SuppressionAnnotation"})</warning>
|
||||
public class A {
|
||||
<warning descr="Inspection suppression annotation '@SuppressWarnings(\"PublicField\")'">@SuppressWarnings("PublicField")</warning>
|
||||
public String s;
|
||||
<warning descr="Inspection suppression annotation '@SuppressWarnings({})'">@SuppressWarnings({})</warning>
|
||||
public String t;
|
||||
|
||||
void foo() {
|
||||
<warning descr="Inspection suppression annotation '//noinspection HardCodedStringLiteral'">//noinspection HardCodedStringLiteral</warning>
|
||||
System.out.println("hello");
|
||||
<warning descr="Inspection suppression annotation '// noinspection'">// noinspection</warning>
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
@SuppressWarnings("FreeSpeech")
|
||||
void bar() {
|
||||
//noinspection FreeSpeech
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
fileName = "A"
|
||||
)
|
||||
}
|
||||
|
||||
fun `test quickfix - remove annotation`() {
|
||||
myFixture.testQuickFix(JvmLanguage.JAVA, """
|
||||
public class A {
|
||||
@SuppressWarnings("PublicField", "Hard<caret>CodedStringLiteral")
|
||||
public String s = "test";
|
||||
}
|
||||
""".trimIndent(), """
|
||||
public class A {
|
||||
public String s = "test";
|
||||
}
|
||||
""".trimIndent(), "Remove '@SuppressWarnings' annotation", testPreview = true)
|
||||
}
|
||||
|
||||
fun `test quickfix - remove comment`() {
|
||||
myFixture.testQuickFix(JvmLanguage.JAVA, """
|
||||
public class A {
|
||||
//noinspection PublicField, Hard<caret>CodedStringLiteral
|
||||
public String s = "test";
|
||||
}
|
||||
""".trimIndent(), """
|
||||
public class A {
|
||||
public String s = "test";
|
||||
}
|
||||
""".trimIndent(), "Remove //noinspection", testPreview = true)
|
||||
}
|
||||
|
||||
fun `test quickfix - allow a single suppression from annotation`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.JAVA, """
|
||||
public class A {
|
||||
@SuppressWarnings("Public<caret>Field")
|
||||
public String s = "test";
|
||||
}
|
||||
""".trimIndent(), "PublicField")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow a single suppression from annotation when array form used`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.JAVA, """
|
||||
public class A {
|
||||
@SuppressWarnings({"Public<caret>Field"})
|
||||
public String s = "test";
|
||||
}
|
||||
""".trimIndent(), "PublicField")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow a single suppression from annotation when explicit attribute name exists`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.JAVA, """
|
||||
public class A {
|
||||
@SuppressWarnings(value = "Public<caret>Field")
|
||||
public String s = "test";
|
||||
}
|
||||
""".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 {
|
||||
@SuppressWarnings({"Public<caret>Field", "HardCodedStringLiteral"})
|
||||
public String s = "test";
|
||||
}
|
||||
""".trimIndent(), "PublicField", "HardCodedStringLiteral")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow multiple suppressions from annotation when explicit attribute name exists`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.JAVA, """
|
||||
public class A {
|
||||
@SuppressWarnings(value = {"Public<caret>Field", "HardCodedStringLiteral"})
|
||||
public String s = "test";
|
||||
}
|
||||
""".trimIndent(), "PublicField", "HardCodedStringLiteral")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow multiple suppressions from annotation when constants used`() {
|
||||
myFixture.addClass("""
|
||||
public final class Constants {
|
||||
public static final String PUBLIC_FIELD = "PublicField";
|
||||
public static final String HARD_CODED_STRING_LITERAL = "HardCodedStringLiteral";
|
||||
}
|
||||
""".trimIndent())
|
||||
testAllowSuppressionQuickFix(JvmLanguage.JAVA, """
|
||||
public class A {
|
||||
@Suppress<caret>Warnings({Constants.PUBLIC_FIELD, Constants.HARD_CODED_STRING_LITERAL})
|
||||
public String s = "test";
|
||||
}
|
||||
""".trimIndent(), "PublicField", "HardCodedStringLiteral")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow a single suppression from comment`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.JAVA, """
|
||||
public class A {
|
||||
//noinspection Public<caret>Field
|
||||
public String s = "test";
|
||||
}
|
||||
""".trimIndent(), "PublicField")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow multiple suppressions from comment`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.JAVA, """
|
||||
public class A {
|
||||
//noinspection Public<caret>Field, Hard<caret>CodedStringLiteral
|
||||
public String s = "test";
|
||||
}
|
||||
""".trimIndent(), "PublicField", "HardCodedStringLiteral")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.SuppressionAnnotationInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
|
||||
class KotlinSuppressionAnnotationInspectionTest : SuppressionAnnotationInspectionTestBase() {
|
||||
|
||||
fun `test highlighting`() {
|
||||
inspection.myAllowedSuppressions.add("FreeSpeech")
|
||||
myFixture.testHighlighting(
|
||||
JvmLanguage.KOTLIN,
|
||||
"""
|
||||
<warning descr="Inspection suppression annotation '@Suppress(\"ALL\", \"SuppressionAnnotation\")'">@Suppress("ALL", "SuppressionAnnotation")</warning>
|
||||
class A {
|
||||
<warning descr="Inspection suppression annotation '@Suppress(\"PublicField\")'">@Suppress("PublicField")</warning>
|
||||
var s: String? = null
|
||||
<warning descr="Inspection suppression annotation '@Suppress'">@Suppress</warning>
|
||||
var t: String? = null
|
||||
|
||||
fun foo() {
|
||||
<warning descr="Inspection suppression annotation '//noinspection HardCodedStringLiteral'">//noinspection HardCodedStringLiteral</warning>
|
||||
any("hello")
|
||||
<warning descr="Inspection suppression annotation '// noinspection'">// noinspection</warning>
|
||||
any()
|
||||
}
|
||||
|
||||
@Suppress("FreeSpeech")
|
||||
fun bar() {
|
||||
// noinspection FreeSpeech
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
private fun any(s: String? = null): String? = s
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
fun `test quickfix - remove annotation`() {
|
||||
myFixture.testQuickFix(JvmLanguage.KOTLIN, """
|
||||
class A {
|
||||
@Suppress("PublicField", "Hard<caret>CodedStringLiteral")
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), """
|
||||
class A {
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "Remove '@Suppress' annotation", testPreview = true)
|
||||
}
|
||||
|
||||
fun `test quickfix - remove comment`() {
|
||||
myFixture.testQuickFix(JvmLanguage.KOTLIN, """
|
||||
class A {
|
||||
//noinspection PublicField, Hard<caret>CodedStringLiteral
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), """
|
||||
class A {
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "Remove //noinspection", testPreview = true)
|
||||
}
|
||||
|
||||
fun `test quickfix - allow a single suppression from annotation`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.KOTLIN, """
|
||||
class A {
|
||||
@Suppress("Public<caret>Field")
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "PublicField")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow a single suppression from annotation when array form used`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.KOTLIN, """
|
||||
class A {
|
||||
@Suppress(["Public<caret>Field"])
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "PublicField")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow a single suppression from annotation when explicit attribute name exists`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.KOTLIN, """
|
||||
class A {
|
||||
@Suppress(names = "Public<caret>Field")
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "PublicField")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow multiple suppressions from annotation`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.KOTLIN, """
|
||||
class A {
|
||||
@Suppress("Public<caret>Field", "HardCodedStringLiteral")
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "PublicField", "HardCodedStringLiteral")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow multiple suppressions from annotation when array form used`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.KOTLIN, """
|
||||
class A {
|
||||
@Suppress(["Public<caret>Field", "HardCodedStringLiteral"])
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "PublicField", "HardCodedStringLiteral")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow multiple suppressions from annotation when explicit attribute name exists`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.KOTLIN, """
|
||||
class A {
|
||||
@Suppress(names = ["Public<caret>Field", "HardCodedStringLiteral"])
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "PublicField", "HardCodedStringLiteral")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow multiple suppressions from annotation when constants used`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.KOTLIN, """
|
||||
object Constants {
|
||||
const val PUBLIC_FIELD = "PublicField"
|
||||
const val HARD_CODED_STRING_LITERAL = "HardCodedStringLiteral"
|
||||
}
|
||||
|
||||
class A {
|
||||
@Suppress([Constants.PUBLIC_<caret>FIELD, Constants.HARD_CODED_STRING_LITERAL])
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "PublicField", "HardCodedStringLiteral")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow a single suppression from comment`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.KOTLIN, """
|
||||
class A {
|
||||
//noinspection Public<caret>Field
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "PublicField")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow multiple suppressions from comment`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.KOTLIN, """
|
||||
class A {
|
||||
//noinspection Public<caret>Field, Hard<caret>CodedStringLiteral
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "PublicField", "HardCodedStringLiteral")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// 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.CommonQuickFixBundle
|
||||
import com.intellij.codeInspection.IntentionWrapper
|
||||
import com.intellij.codeInspection.LocalQuickFix
|
||||
import com.intellij.codeInspection.SuppressionAnnotationUtil
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
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 }
|
||||
}
|
||||
|
||||
override fun getRemoveAnnotationQuickFix(annotation: PsiElement): LocalQuickFix? {
|
||||
if (annotation is KtAnnotationEntry) {
|
||||
val fix = RemoveAnnotationFix(CommonQuickFixBundle.message("fix.remove.annotation.text", "Suppress"), annotation)
|
||||
return IntentionWrapper.wrapToQuickFixes(arrayOf(fix), annotation.containingFile).takeIf { it.size == 1 }?.first()
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -118,6 +118,10 @@
|
||||
|
||||
<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