mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-16 14:23:28 +07:00
IJPL-160728 SuppressDetectingInspection can be non-dumb aware
GitOrigin-RevId: e76b9fb448e6a38d23249684dc77b4e44d8911a9
This commit is contained in:
committed by
intellij-monorepo-bot
parent
0980161ec9
commit
c4476fce2c
@@ -4,17 +4,14 @@ package com.intellij.codeInsight.daemon.impl
|
||||
import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase
|
||||
import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase.CanChangeDocumentDuringHighlighting
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
|
||||
import com.intellij.codeInspection.LocalInspectionEP
|
||||
import com.intellij.codeInspection.LocalInspectionTool
|
||||
import com.intellij.codeInspection.LocalInspectionToolSession
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.codeInspection.*
|
||||
import com.intellij.codeInspection.ex.LocalInspectionToolWrapper
|
||||
import com.intellij.ide.highlighter.JavaFileType
|
||||
import com.intellij.lang.java.JavaLanguage
|
||||
import com.intellij.openapi.project.DumbAware
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.use
|
||||
import com.intellij.psi.PsiComment
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.testFramework.*
|
||||
import org.intellij.lang.annotations.Language
|
||||
import java.util.*
|
||||
@@ -26,10 +23,11 @@ class LocalInspectionsInDumbModeTest : DaemonAnalyzerTestCase() {
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
DaemonProgressIndicator.setDebug(true)
|
||||
enableInspectionTools(project, testRootDisposable, DumbInspection(), SmartInspection())
|
||||
}
|
||||
|
||||
fun testLocalInspectionInDumbMode() {
|
||||
enableInspectionTools(project, testRootDisposable, DumbInspection(), SmartInspection())
|
||||
|
||||
@Language("JAVA")
|
||||
val text = """
|
||||
// comment
|
||||
@@ -57,6 +55,8 @@ class LocalInspectionsInDumbModeTest : DaemonAnalyzerTestCase() {
|
||||
}
|
||||
|
||||
fun testLocalInspectionsInSmartModeThenInDumbMode() {
|
||||
enableInspectionTools(project, testRootDisposable, DumbInspection(), SmartInspection())
|
||||
|
||||
@Language("JAVA")
|
||||
val text = """
|
||||
// comment
|
||||
@@ -78,6 +78,8 @@ class LocalInspectionsInDumbModeTest : DaemonAnalyzerTestCase() {
|
||||
}
|
||||
|
||||
fun testLocalInspectionInDumbModeDontInitializeUnrelatedTools() {
|
||||
enableInspectionTools(project, testRootDisposable, DumbInspection(), SmartInspection())
|
||||
|
||||
val unrelatedToolWrapper = createUnrelatedToolWrapper()
|
||||
enableInspectionTool(project, unrelatedToolWrapper, testRootDisposable)
|
||||
LocalInspectionsPass.forceNoDuplicateCheckInTests(testRootDisposable)
|
||||
@@ -94,6 +96,8 @@ class LocalInspectionsInDumbModeTest : DaemonAnalyzerTestCase() {
|
||||
}
|
||||
|
||||
fun testLocalInspectionDontInitializeUnrelatedTools() {
|
||||
enableInspectionTools(project, testRootDisposable, DumbInspection(), SmartInspection())
|
||||
|
||||
val unrelatedToolWrapper = createUnrelatedToolWrapper()
|
||||
enableInspectionTool(project, unrelatedToolWrapper, testRootDisposable)
|
||||
LocalInspectionsPass.forceNoDuplicateCheckInTests(testRootDisposable)
|
||||
@@ -109,6 +113,86 @@ class LocalInspectionsInDumbModeTest : DaemonAnalyzerTestCase() {
|
||||
assertFalse(unrelatedToolWrapper.isToolInstantiated())
|
||||
}
|
||||
|
||||
fun testJavaSuppressor() {
|
||||
enableInspectionTools(project, testRootDisposable, RedundantSuppressInspection(), StringInspection())
|
||||
|
||||
val javaRedundantSuppressor = LanguageInspectionSuppressors.INSTANCE.allForLanguage(JavaLanguage.INSTANCE)
|
||||
.filterIsInstance<RedundantSuppressionDetector>()
|
||||
.firstOrNull() // Java Redundant Suppressor is expected to exist
|
||||
requireNotNull(javaRedundantSuppressor) // Java Redundant Suppressor is expected to exist
|
||||
assertFalse(javaRedundantSuppressor.isDumbAware) // update the test if JavaRedundantSuppressor has become dumb-aware
|
||||
|
||||
@Language("JAVA")
|
||||
val text = """
|
||||
class A {
|
||||
void foo() {
|
||||
//noinspection String
|
||||
Object s = "abc";
|
||||
}
|
||||
}
|
||||
"""
|
||||
configureByText(JavaFileType.INSTANCE, text)
|
||||
|
||||
// smart infos don't contain String because Suppressor works in smart mode and suppresses it
|
||||
val smartInfos = doHighlighting().map { it.description }
|
||||
assertDoesntContain(smartInfos, "String")
|
||||
|
||||
// dumb infos contain String because Suppressor does not work in dumb mode
|
||||
val dumbInfos = doHighlightingInDumbMode().map { it.description }
|
||||
assertContainsElements(dumbInfos, "String")
|
||||
}
|
||||
|
||||
fun testRedundantJavaSuppression() {
|
||||
enableInspectionTools(project, testRootDisposable, RedundantSuppressInspection(), StringInspection())
|
||||
|
||||
val javaRedundantSuppressor = LanguageInspectionSuppressors.INSTANCE.allForLanguage(JavaLanguage.INSTANCE)
|
||||
.filterIsInstance<RedundantSuppressionDetector>()
|
||||
.firstOrNull()
|
||||
assertNotNull(javaRedundantSuppressor)// Java Redundant Suppressor is expected to exist
|
||||
|
||||
@Language("JAVA")
|
||||
val text = """
|
||||
class A {
|
||||
void foo() {
|
||||
//noinspection String
|
||||
Object s;
|
||||
}
|
||||
}
|
||||
"""
|
||||
configureByText(JavaFileType.INSTANCE, text)
|
||||
|
||||
// dumb infos contain a redundant suppression because it's not removed as java suppressor does not work in dumb mode
|
||||
val initialDumbInfos = doHighlightingInDumbMode().map { it.description }
|
||||
assertDoesntContain(initialDumbInfos, "Redundant suppression")
|
||||
|
||||
// smart infos contain a redundant suppression, because suppression is in fact redundant,
|
||||
// and redundant suppressor for Java works in smart mode
|
||||
val smartInfos = doHighlighting().map { it.description }
|
||||
assertContainsElements(smartInfos, "Redundant suppression")
|
||||
|
||||
// dumb infos contain a redundant suppression because it's not removed as java suppressor does not work in dumb mode
|
||||
val dumbInfos = doHighlightingInDumbMode().map { it.description }
|
||||
assertContainsElements(dumbInfos, "Redundant suppression")
|
||||
}
|
||||
|
||||
|
||||
fun testSuppressorInDumbMode2() {
|
||||
enableInspectionTools(project, testRootDisposable, RedundantSuppressInspection(), StringInspection())
|
||||
|
||||
@Language("JAVA")
|
||||
val text = """
|
||||
class A {
|
||||
void foo() {
|
||||
Object s = "abc";
|
||||
}
|
||||
}
|
||||
"""
|
||||
configureByText(JavaFileType.INSTANCE, text)
|
||||
|
||||
val dumbInfos = doHighlightingInDumbMode()
|
||||
assertDoesntContain(dumbInfos, "String")
|
||||
}
|
||||
|
||||
private fun assertExistsInfo(infos: List<HighlightInfo>, text: String) {
|
||||
assert(infos.any { it.description == text }) {
|
||||
"List [${infos.joinToString { it.description }}] does not contain `$text`"
|
||||
@@ -154,6 +238,17 @@ class LocalInspectionsInDumbModeTest : DaemonAnalyzerTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
private class StringInspection : LocalInspectionTool(), DumbAware {
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
|
||||
return object : JavaElementVisitor() {
|
||||
override fun visitLiteralExpression(expression: PsiLiteralExpression) {
|
||||
holder.registerProblem(expression, "String")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun createUnrelatedToolWrapper(): UnrelatedToolWrapper {
|
||||
val ep = LocalInspectionEP()
|
||||
ep.dumbAware = true
|
||||
|
||||
@@ -1532,6 +1532,7 @@ com.intellij.codeInspection.QuickFix
|
||||
- a:getFamilyName():java.lang.String
|
||||
- getName():java.lang.String
|
||||
com.intellij.codeInspection.RedundantSuppressionDetector
|
||||
- com.intellij.openapi.project.PossiblyDumbAware
|
||||
- a:createRemoveRedundantSuppressionFix(java.lang.String):com.intellij.codeInspection.LocalQuickFix
|
||||
- getHighlightingRange(com.intellij.psi.PsiElement,java.lang.String):com.intellij.openapi.util.TextRange
|
||||
- a:getSuppressionIds(com.intellij.psi.PsiElement):java.lang.String
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 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.openapi.project.PossiblyDumbAware;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
@@ -9,7 +10,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
||||
public interface RedundantSuppressionDetector {
|
||||
public interface RedundantSuppressionDetector extends PossiblyDumbAware {
|
||||
|
||||
/**
|
||||
* @return comma separated list of suppress ids configured in this {@code element}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 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.AnalysisScope;
|
||||
@@ -384,5 +384,10 @@ public abstract class RedundantSuppressInspectionBase extends GlobalSimpleInspec
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDumbAware() {
|
||||
return mySuppressor.isDumbAware();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ class InspectionRunner {
|
||||
InspectionEngine.withSession(myPsiFile, myRestrictRange, finalPriorityRange, minimumSeverity, myIsOnTheFly, session -> {
|
||||
for (LocalInspectionToolWrapper toolWrapper : applicableByLanguage) {
|
||||
if (enabledToolsPredicate == null || enabledToolsPredicate.value(toolWrapper)) {
|
||||
LocalInspectionTool tool = toolWrapper.getTool();
|
||||
LocalInspectionTool tool = toolWrapper.getTool();
|
||||
AtomicInteger toolWasProcessed = new AtomicInteger();
|
||||
ToolStampInfo toolStamps = new ToolStampInfo();
|
||||
InspectionProblemHolder holder = new InspectionProblemHolder(myPsiFile, toolWrapper, myIsOnTheFly, myInspectionProfileWrapper,
|
||||
@@ -207,7 +207,7 @@ class InspectionRunner {
|
||||
InspectionProfilerDataHolder.saveStats(myPsiFile, init, highlightInfoUpdater);
|
||||
}
|
||||
if (myIsOnTheFly && addRedundantSuppressions) {
|
||||
addRedundantSuppressions(init, toolWrappers, redundantContexts, applyIncrementallyCallback, contextFinishedCallback);
|
||||
addRedundantSuppressions(init, toolWrappers, redundantContexts, applyIncrementallyCallback, contextFinishedCallback, enabledToolsPredicate);
|
||||
}
|
||||
});
|
||||
return ContainerUtil.concat(init, redundantContexts, injectedContexts);
|
||||
@@ -294,7 +294,8 @@ class InspectionRunner {
|
||||
@NotNull List<? extends LocalInspectionToolWrapper> toolWrappers,
|
||||
@NotNull List<? super InspectionContext> result,
|
||||
@NotNull ApplyIncrementallyCallback applyIncrementallyCallback,
|
||||
@NotNull Consumer<? super InspectionContext> contextFinishedCallback) {
|
||||
@NotNull Consumer<? super InspectionContext> contextFinishedCallback,
|
||||
@Nullable Condition<? super LocalInspectionToolWrapper> enabledToolsPredicate) {
|
||||
for (InspectionContext context : init) {
|
||||
LocalInspectionToolWrapper toolWrapper = context.tool;
|
||||
LocalInspectionTool tool = toolWrapper.getTool();
|
||||
@@ -310,20 +311,33 @@ class InspectionRunner {
|
||||
if (redundantSuppressionKey == null || !inspectionProfile.isToolEnabled(redundantSuppressionKey, myPsiFile)) {
|
||||
return;
|
||||
}
|
||||
InspectionToolWrapper<?, ?> redundantSuppressTool = Objects.requireNonNull(
|
||||
inspectionProfile.getInspectionTool(RedundantSuppressInspectionBase.SHORT_NAME, myPsiFile),
|
||||
"inspectionProfile.isToolEnabled(redundantSuppressionKey, myPsiFile) return true, thus an instance must be not-null"
|
||||
);
|
||||
|
||||
Language fileLanguage = myPsiFile.getLanguage();
|
||||
InspectionSuppressor suppressor = ContainerUtil.find(LanguageInspectionSuppressors.INSTANCE.allForLanguage(fileLanguage), s -> s instanceof RedundantSuppressionDetector);
|
||||
if (!(suppressor instanceof RedundantSuppressionDetector redundantSuppressionDetector)) {
|
||||
return;
|
||||
}
|
||||
Set<String> activeTools = new HashSet<>();
|
||||
|
||||
RedundantSuppressionDetector redundantSuppressionDetector = findSuppressionDetector(fileLanguage);
|
||||
if (redundantSuppressionDetector == null) return;
|
||||
|
||||
// todo do we really need toolWrappers to figure out active tools?
|
||||
// I believe `init` parameter already has the correct list of active tools???
|
||||
Set<String> activeTools = new HashSet<>();
|
||||
for (LocalInspectionToolWrapper tool : toolWrappers) {
|
||||
if (tool.runForWholeFile()) {
|
||||
// no redundants for whole file tools pass
|
||||
continue;
|
||||
}
|
||||
if (tool.isUnfair() || !tool.isApplicable(fileLanguage) || myInspectionProfileWrapper.getInspectionTool(tool.getShortName(), myPsiFile) instanceof GlobalInspectionToolWrapper) {
|
||||
|
||||
if (tool.isUnfair() ||
|
||||
!tool.isApplicable(fileLanguage) ||
|
||||
myInspectionProfileWrapper.getInspectionTool(tool.getShortName(), myPsiFile) instanceof GlobalInspectionToolWrapper ||
|
||||
!(enabledToolsPredicate != null && enabledToolsPredicate.test(tool))
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
activeTools.add(tool.getID());
|
||||
ContainerUtil.addIfNotNull(activeTools, tool.getAlternativeID());
|
||||
InspectionElementsMerger elementsMerger = InspectionElementsMerger.getMerger(tool.getShortName());
|
||||
@@ -331,16 +345,28 @@ class InspectionRunner {
|
||||
activeTools.addAll(Arrays.asList(elementsMerger.getSuppressIds()));
|
||||
}
|
||||
}
|
||||
InspectionToolWrapper<?,?> redundantSuppressTool = inspectionProfile.getInspectionTool(RedundantSuppressInspectionBase.SHORT_NAME, myPsiFile);
|
||||
|
||||
RedundantSuppressInspectionBase redundantSuppressGlobalTool = (RedundantSuppressInspectionBase)redundantSuppressTool.getTool();
|
||||
LocalInspectionTool rsLocalTool = redundantSuppressGlobalTool.createLocalTool(redundantSuppressionDetector, mySuppressedElements, activeTools, myRestrictRange);
|
||||
List<LocalInspectionToolWrapper> wrappers = Collections.singletonList(new LocalInspectionToolWrapper(rsLocalTool));
|
||||
LocalInspectionTool rsLocalTool = redundantSuppressGlobalTool.createLocalTool(
|
||||
redundantSuppressionDetector, mySuppressedElements, activeTools, myRestrictRange
|
||||
);
|
||||
LocalInspectionToolWrapper rsWrapper = new LocalInspectionToolWrapper(rsLocalTool);
|
||||
if (enabledToolsPredicate != null && !enabledToolsPredicate.test(rsWrapper)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<LocalInspectionToolWrapper> wrappers = Collections.singletonList(rsWrapper);
|
||||
InspectionRunner runner = new InspectionRunner(myPsiFile, myRestrictRange, myPriorityRange, myInspectInjected, true,
|
||||
myDumbMode, myProgress, false, myInspectionProfileWrapper,
|
||||
mySuppressedElements);
|
||||
result.addAll(runner.inspect(wrappers, HighlightSeverity.WARNING, false, applyIncrementallyCallback, contextFinishedCallback, null));
|
||||
}
|
||||
|
||||
private static @Nullable RedundantSuppressionDetector findSuppressionDetector(@NotNull Language fileLanguage) {
|
||||
List<InspectionSuppressor> allSuppressors = LanguageInspectionSuppressors.INSTANCE.allForLanguage(fileLanguage);
|
||||
return ContainerUtil.findInstance(allSuppressors, RedundantSuppressionDetector.class);
|
||||
}
|
||||
|
||||
private void executeInImpatientReadAction(@NotNull Runnable runnable) {
|
||||
ApplicationEx application = ApplicationManagerEx.getApplicationEx();
|
||||
boolean shouldFailFastAcquiringReadAction = application.isInImpatientReader();
|
||||
|
||||
Reference in New Issue
Block a user