mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-9687 PyUnusedLocalInspection: split into three separate inspections
(cherry picked from commit 6544ea37b7b8db58f8555b9b7c53d7922158f125) GitOrigin-RevId: ae66cceb9c9b6465a8a127937ae736823580313f
This commit is contained in:
committed by
intellij-monorepo-bot
parent
dfa8ca325e
commit
1b2d29fa8c
+7
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
Reports local functions that are defined but never used.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
Reports local variables, parameters, and functions that are locally defined, but not used name in a function.
|
||||
Reports local variables and other local symbols that are locally defined, but not used name in a function.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
Reports parameters of a function that are not used in its body.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -236,6 +236,14 @@
|
||||
"id": "PyUnusedLocalInspection",
|
||||
"codeQualityCategory": "Code Style"
|
||||
},
|
||||
{
|
||||
"id": "PyUnusedParameterInspection",
|
||||
"codeQualityCategory": "Code Style"
|
||||
},
|
||||
{
|
||||
"id": "PyUnusedFunctionInspection",
|
||||
"codeQualityCategory": "Code Style"
|
||||
},
|
||||
{
|
||||
"id": "PyMethodFirstArgAssignmentInspection",
|
||||
"codeQualityCategory": "Reliability"
|
||||
|
||||
@@ -199,6 +199,10 @@
|
||||
<statistics.applicationUsagesCollector implementation="com.jetbrains.python.psi.types.PyTypeEvaluationAggregatesCollector"/>
|
||||
|
||||
<localInspection language="Python" shortName="PyUnusedLocalInspection" suppressId="PyUnusedLocal" bundle="messages.PyPsiBundle" key="INSP.NAME.unused" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WEAK WARNING" implementationClass="com.jetbrains.python.inspections.unusedLocal.PyUnusedLocalInspection"/>
|
||||
<localInspection language="Python" shortName="PyUnusedParameterInspection" suppressId="PyUnusedParameter" bundle="messages.PyPsiBundle" key="INSP.NAME.unused.parameter" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WEAK WARNING" implementationClass="com.jetbrains.python.inspections.unusedLocal.PyUnusedParameterInspection"/>
|
||||
<localInspection language="Python" shortName="PyUnusedFunctionInspection" suppressId="PyUnusedFunction" bundle="messages.PyPsiBundle" key="INSP.NAME.unused.function" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WEAK WARNING" implementationClass="com.jetbrains.python.inspections.unusedLocal.PyUnusedFunctionInspection"/>
|
||||
<inspectionElementsMerger implementation="com.jetbrains.python.inspections.unusedLocal.PyUnusedParameterInspectionMerger"/>
|
||||
<inspectionElementsMerger implementation="com.jetbrains.python.inspections.unusedLocal.PyUnusedFunctionInspectionMerger"/>
|
||||
<localInspection language="Python" shortName="PyRedundantParenthesesInspection" suppressId="PyRedundantParentheses" bundle="messages.PyPsiBundle" key="INSP.NAME.redundant.parentheses" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WEAK WARNING" implementationClass="com.jetbrains.python.inspections.PyRedundantParenthesesInspection"/>
|
||||
<localInspection language="Python" shortName="PySimplifyBooleanCheckInspection" suppressId="PySimplifyBooleanCheck" bundle="messages.PyPsiBundle" key="INSP.NAME.check.can.be.simplified" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WEAK WARNING" implementationClass="com.jetbrains.python.inspections.PySimplifyBooleanCheckInspection"/>
|
||||
<localInspection language="Python" shortName="PyDefaultArgumentInspection" suppressId="PyDefaultArgument" bundle="messages.PyPsiBundle" key="INSP.NAME.default.argument" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WARNING" implementationClass="com.jetbrains.python.inspections.PyDefaultArgumentInspection"/>
|
||||
|
||||
@@ -880,6 +880,8 @@ INSP.mock.patch.too.many.params=Function has {0} extra parameter(s) not matched
|
||||
|
||||
# PyUnusedLocalInspection
|
||||
INSP.NAME.unused=Unused local symbols
|
||||
INSP.NAME.unused.parameter=Unused parameter
|
||||
INSP.NAME.unused.function=Unused function
|
||||
INSP.unused.locals.parameter.isnot.used=Parameter `{0}` value is not used
|
||||
INSP.unused.locals.local.variable.isnot.used=Local variable `{0}` value is not used
|
||||
INSP.unused.locals.replace.with.wildcard=Replace with _
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.inspections.unusedLocal
|
||||
|
||||
/**
|
||||
* Reports unused local functions. Unused local variables and other local symbols are reported separately by
|
||||
* [PyUnusedLocalInspection]; both inspections share [PyUnusedLocalInspectionVisitor] for the analysis.
|
||||
*/
|
||||
class PyUnusedFunctionInspection : PyUnusedSymbolInspection() {
|
||||
override val reportTarget: PyUnusedLocalInspectionVisitor.ReportTarget
|
||||
get() = PyUnusedLocalInspectionVisitor.ReportTarget.FUNCTIONS
|
||||
}
|
||||
+3
-3
@@ -19,7 +19,6 @@ public final class PyUnusedLocalInspection extends PyInspection {
|
||||
private static final Key<PyUnusedLocalInspectionVisitor> KEY = Key.create("PyUnusedLocal.Visitor");
|
||||
|
||||
public boolean ignoreTupleUnpacking = true;
|
||||
public boolean ignoreLambdaParameters = true;
|
||||
public boolean ignoreLoopIterationVariables = true;
|
||||
public boolean ignoreVariablesStartingWithUnderscore = true;
|
||||
|
||||
@@ -29,9 +28,11 @@ public final class PyUnusedLocalInspection extends PyInspection {
|
||||
@NotNull LocalInspectionToolSession session) {
|
||||
final PyUnusedLocalInspectionVisitor visitor = new PyUnusedLocalInspectionVisitor(holder,
|
||||
ignoreTupleUnpacking,
|
||||
ignoreLambdaParameters,
|
||||
true,
|
||||
ignoreLoopIterationVariables,
|
||||
ignoreVariablesStartingWithUnderscore,
|
||||
PyUnusedLocalInspectionVisitor.ReportTarget.LOCALS,
|
||||
PyUnusedLocalInspectionVisitor.getSharedAnalysis(session),
|
||||
PyInspectionVisitor.getContext(session));
|
||||
// buildVisitor() will be called on injected files in the same session - don't overwrite if we already have one
|
||||
final PyUnusedLocalInspectionVisitor existingVisitor = session.getUserData(KEY);
|
||||
@@ -54,7 +55,6 @@ public final class PyUnusedLocalInspection extends PyInspection {
|
||||
public @NotNull OptPane getOptionsPane() {
|
||||
return pane(
|
||||
checkbox("ignoreTupleUnpacking", PyPsiBundle.message("INSP.unused.locals.ignore.variables.used.in.tuple.unpacking")),
|
||||
checkbox("ignoreLambdaParameters", PyPsiBundle.message("INSP.unused.locals.ignore.lambda.parameters")),
|
||||
checkbox("ignoreLoopIterationVariables", PyPsiBundle.message("INSP.unused.locals.ignore.range.iteration.variables")),
|
||||
checkbox("ignoreVariablesStartingWithUnderscore", PyPsiBundle.message("INSP.unused.locals.ignore.variables.starting.with"))
|
||||
);
|
||||
|
||||
+72
-5
@@ -3,6 +3,7 @@ package com.jetbrains.python.inspections.unusedLocal;
|
||||
|
||||
import com.intellij.codeInsight.controlflow.ControlFlowUtil;
|
||||
import com.intellij.codeInsight.controlflow.Instruction;
|
||||
import com.intellij.codeInspection.LocalInspectionToolSession;
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemHighlightType;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
@@ -10,6 +11,7 @@ import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.modcommand.ModPsiUpdater;
|
||||
import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -102,23 +104,64 @@ public final class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor {
|
||||
private final boolean myIgnoreLambdaParameters;
|
||||
private final boolean myIgnoreRangeIterationVariables;
|
||||
private final boolean myIgnoreVariablesStartingWithUnderscore;
|
||||
private final ReportTarget myReportTarget;
|
||||
private final SharedAnalysis mySharedAnalysis;
|
||||
|
||||
/** Which kind of unused element this visitor reports; each kind is exposed as a separate inspection. */
|
||||
public enum ReportTarget { LOCALS, PARAMETERS, FUNCTIONS }
|
||||
|
||||
/**
|
||||
* Analysis state shared by the unused-locals, unused-parameter, and unused-function inspections. All three perform the same
|
||||
* control-flow analysis but report different element kinds; sharing this state through the {@link LocalInspectionToolSession}
|
||||
* keeps the heavy analysis running once per file instead of once per inspection.
|
||||
*/
|
||||
public static final class SharedAnalysis {
|
||||
// Names defined directly in a scope. They all belong to this scope.
|
||||
private final Map<ScopeOwner, @Unmodifiable Set<PsiElement>> scopeWrites = new ConcurrentHashMap<>();
|
||||
// Names read directly in a scope. They might belong to some outer scope.
|
||||
private final Map<ScopeOwner, @Unmodifiable Set<PsiElement>> scopeReads = new ConcurrentHashMap<>();
|
||||
private volatile Set<PsiElement> unusedElements;
|
||||
}
|
||||
|
||||
private static final Key<SharedAnalysis> SHARED_ANALYSIS_KEY = Key.create("PyUnusedLocal.SharedAnalysis");
|
||||
|
||||
/** Returns the analysis state shared by the unused-symbol inspections running on this session, creating it on first use. */
|
||||
public static @NotNull SharedAnalysis getSharedAnalysis(@NotNull LocalInspectionToolSession session) {
|
||||
SharedAnalysis analysis = session.getUserData(SHARED_ANALYSIS_KEY);
|
||||
if (analysis == null) {
|
||||
synchronized (SHARED_ANALYSIS_KEY) {
|
||||
analysis = session.getUserData(SHARED_ANALYSIS_KEY);
|
||||
if (analysis == null) {
|
||||
analysis = new SharedAnalysis();
|
||||
session.putUserData(SHARED_ANALYSIS_KEY, analysis);
|
||||
}
|
||||
}
|
||||
}
|
||||
return analysis;
|
||||
}
|
||||
|
||||
// Names defined directly in a scope. They all belong to this scope.
|
||||
private final Map<ScopeOwner, @Unmodifiable Set<PsiElement>> myScopeWrites = new ConcurrentHashMap<>();
|
||||
private final Map<ScopeOwner, @Unmodifiable Set<PsiElement>> myScopeWrites;
|
||||
// Names read directly in a scope. They might belong to some outer scope.
|
||||
private final Map<ScopeOwner, @Unmodifiable Set<PsiElement>> myScopeReads = new ConcurrentHashMap<>();
|
||||
private final Map<ScopeOwner, @Unmodifiable Set<PsiElement>> myScopeReads;
|
||||
|
||||
public PyUnusedLocalInspectionVisitor(@NotNull ProblemsHolder holder,
|
||||
boolean ignoreTupleUnpacking,
|
||||
boolean ignoreLambdaParameters,
|
||||
boolean ignoreRangeIterationVariables,
|
||||
boolean ignoreVariablesStartingWithUnderscore,
|
||||
@NotNull ReportTarget reportTarget,
|
||||
@NotNull SharedAnalysis sharedAnalysis,
|
||||
@NotNull TypeEvalContext context) {
|
||||
super(holder, context);
|
||||
myIgnoreTupleUnpacking = ignoreTupleUnpacking;
|
||||
myIgnoreLambdaParameters = ignoreLambdaParameters;
|
||||
myIgnoreRangeIterationVariables = ignoreRangeIterationVariables;
|
||||
myIgnoreVariablesStartingWithUnderscore = ignoreVariablesStartingWithUnderscore;
|
||||
myReportTarget = reportTarget;
|
||||
mySharedAnalysis = sharedAnalysis;
|
||||
myScopeWrites = sharedAnalysis.scopeWrites;
|
||||
myScopeReads = sharedAnalysis.scopeReads;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -150,6 +193,10 @@ public final class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor {
|
||||
}
|
||||
|
||||
private void collectAllWrites(ScopeOwner owner) {
|
||||
if (myScopeWrites.containsKey(owner)) {
|
||||
// Already computed for another unused-symbol inspection sharing this session.
|
||||
return;
|
||||
}
|
||||
Set<PsiElement> scopeWrites = new HashSet<>();
|
||||
// type parameter list is not included in CFG
|
||||
if (owner instanceof PyTypeParameterListOwner typeParameterListOwner) {
|
||||
@@ -379,6 +426,16 @@ public final class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static @NotNull ReportTarget categorize(@NotNull PsiElement element) {
|
||||
if (element instanceof PyNamedParameter || element.getParent() instanceof PyNamedParameter) {
|
||||
return ReportTarget.PARAMETERS;
|
||||
}
|
||||
if (element instanceof PyFunction) {
|
||||
return ReportTarget.FUNCTIONS;
|
||||
}
|
||||
return ReportTarget.LOCALS;
|
||||
}
|
||||
|
||||
public void registerProblems() {
|
||||
final List<PyInspectionExtension> filters = PyInspectionExtension.EP_NAME.getExtensionList();
|
||||
// Register problems
|
||||
@@ -386,11 +443,21 @@ public final class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor {
|
||||
final Set<PyFunction> functionsWithInheritors = new HashSet<>();
|
||||
final Map<PyFunction, Boolean> emptyFunctions = new HashMap<>();
|
||||
|
||||
Set<PsiElement> unusedElements = StreamEx.of(myScopeWrites.entrySet())
|
||||
.flatCollection(writeEntry -> ContainerUtil.subtract(writeEntry.getValue(), getReadsInsideScope(writeEntry.getKey())))
|
||||
.toImmutableSet();
|
||||
Set<PsiElement> unusedElements = mySharedAnalysis.unusedElements;
|
||||
if (unusedElements == null) {
|
||||
unusedElements = StreamEx.of(myScopeWrites.entrySet())
|
||||
.flatCollection(writeEntry -> ContainerUtil.subtract(writeEntry.getValue(), getReadsInsideScope(writeEntry.getKey())))
|
||||
.toImmutableSet();
|
||||
// Benign race: concurrent inspections may recompute the identical set; the last write wins.
|
||||
mySharedAnalysis.unusedElements = unusedElements;
|
||||
}
|
||||
|
||||
for (PsiElement element : unusedElements) {
|
||||
// Parameters, functions, and the remaining "local symbols" are each reported by a separate inspection.
|
||||
if (categorize(element) != myReportTarget) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean ignoreUnused = false;
|
||||
for (PyInspectionExtension filter : filters) {
|
||||
if (filter.ignoreUnused(element, myTypeEvalContext)) {
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.inspections.unusedLocal
|
||||
|
||||
import com.intellij.codeInspection.options.OptPane
|
||||
import com.intellij.codeInspection.options.OptPane.pane
|
||||
import com.jetbrains.python.PyPsiBundle
|
||||
|
||||
/**
|
||||
* Reports unused function parameters. Unused local variables and other local symbols are reported separately by
|
||||
* [PyUnusedLocalInspection]; both inspections share [PyUnusedLocalInspectionVisitor] for the analysis.
|
||||
*/
|
||||
class PyUnusedParameterInspection : PyUnusedSymbolInspection() {
|
||||
@JvmField
|
||||
var ignoreLambdaParameters: Boolean = true
|
||||
|
||||
override val reportTarget: PyUnusedLocalInspectionVisitor.ReportTarget
|
||||
get() = PyUnusedLocalInspectionVisitor.ReportTarget.PARAMETERS
|
||||
|
||||
override fun shouldIgnoreLambdaParameters(): Boolean = ignoreLambdaParameters
|
||||
|
||||
override fun getOptionsPane(): OptPane = pane(
|
||||
OptPane.checkbox("ignoreLambdaParameters", PyPsiBundle.message("INSP.unused.locals.ignore.lambda.parameters")),
|
||||
)
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.inspections.unusedLocal
|
||||
|
||||
import com.intellij.codeInspection.LocalInspectionToolSession
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.openapi.application.runReadActionBlocking
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import com.jetbrains.python.inspections.PyInspection
|
||||
import com.jetbrains.python.inspections.PyInspectionVisitor
|
||||
|
||||
/**
|
||||
* Base class for the unused-parameter and unused-function inspections. Both report a single kind of unused symbol via the shared
|
||||
* [PyUnusedLocalInspectionVisitor]; the actual control-flow analysis is shared across all unused-symbol inspections running on the
|
||||
* same session (see [PyUnusedLocalInspectionVisitor.SharedAnalysis]). Unused local variables and other local symbols are reported
|
||||
* separately by [PyUnusedLocalInspection].
|
||||
*/
|
||||
abstract class PyUnusedSymbolInspection : PyInspection() {
|
||||
private val visitorKey = Key.create<PyUnusedLocalInspectionVisitor>("${javaClass.simpleName}.Visitor")
|
||||
|
||||
/** The single element kind this inspection reports. */
|
||||
protected abstract val reportTarget: PyUnusedLocalInspectionVisitor.ReportTarget
|
||||
|
||||
/** Whether lambda parameters should be ignored; only meaningful when [reportTarget] is `PARAMETERS`. */
|
||||
protected open fun shouldIgnoreLambdaParameters(): Boolean = true
|
||||
|
||||
final override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
|
||||
val visitor = PyUnusedLocalInspectionVisitor(holder, false, shouldIgnoreLambdaParameters(), false, false,
|
||||
reportTarget,
|
||||
PyUnusedLocalInspectionVisitor.getSharedAnalysis(session),
|
||||
PyInspectionVisitor.getContext(session))
|
||||
// buildVisitor() will be called on injected files in the same session - don't overwrite if we already have one
|
||||
if (session.getUserData(visitorKey) == null) {
|
||||
session.putUserData(visitorKey, visitor)
|
||||
}
|
||||
return visitor
|
||||
}
|
||||
|
||||
final override fun inspectionFinished(session: LocalInspectionToolSession, holder: ProblemsHolder) {
|
||||
val visitor = session.getUserData(visitorKey) ?: return
|
||||
runReadActionBlocking { visitor.registerProblems() }
|
||||
session.putUserData(visitorKey, null)
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.inspections.unusedLocal
|
||||
|
||||
import com.intellij.codeInspection.ex.InspectionElementsMergerBase
|
||||
import org.jdom.Element
|
||||
|
||||
/**
|
||||
* Migrates user inspection-profile settings (enabled state, severity, and shared options such as `ignoreLambdaParameters`) from
|
||||
* the former combined `PyUnusedLocalInspection` to the inspection that took over part of its reporting after PY-9687 split it into
|
||||
* separate unused-local / unused-parameter / unused-function inspections. Without this, a user who had disabled or reconfigured
|
||||
* `PyUnusedLocalInspection` would silently get the new inspections back at their defaults.
|
||||
*
|
||||
* Suppression is intentionally NOT inherited: `# noinspection PyUnusedLocal` no longer silences parameters or functions (the split
|
||||
* is a deliberate clean break), so [getSuppressIds] returns only this inspection's own id instead of letting the base fall back to
|
||||
* the source tool name.
|
||||
*/
|
||||
abstract class PyUnusedSymbolInspectionMerger : InspectionElementsMergerBase() {
|
||||
/** Suppress id of the merged (new) inspection. */
|
||||
protected abstract val mergedSuppressId: String
|
||||
|
||||
final override fun getSourceToolNames(): Array<String> = arrayOf(SOURCE_TOOL_NAME)
|
||||
|
||||
final override fun getSuppressIds(): Array<String> = arrayOf(mergedSuppressId)
|
||||
|
||||
final override fun merge(inspectionElements: Map<String, Element>): Element? {
|
||||
val merged = super.merge(inspectionElements)
|
||||
if (merged != null) return merged
|
||||
// super.merge() produces nothing when the source node carried no option children (e.g. a plain enable/disable toggle or a
|
||||
// severity change). Still carry over the enabled state and severity so the split stays transparent to such users.
|
||||
val source = inspectionElements[SOURCE_TOOL_NAME] ?: return null
|
||||
return Element(INSPECTION_TOOL_TAG).apply {
|
||||
setAttribute(CLASS_ATTR, mergedToolName)
|
||||
source.getAttributeValue(ENABLED_ATTR)?.let { setAttribute(ENABLED_ATTR, it) }
|
||||
source.getAttributeValue(ENABLED_BY_DEFAULT_ATTR)?.let { setAttribute(ENABLED_BY_DEFAULT_ATTR, it) }
|
||||
source.getAttributeValue(LEVEL_ATTR)?.let { setAttribute(LEVEL_ATTR, it) }
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val SOURCE_TOOL_NAME = "PyUnusedLocalInspection"
|
||||
|
||||
// Inspection-profile serialization names (mirror InspectionProfileImpl/ToolsImpl, which are not visible from here).
|
||||
const val INSPECTION_TOOL_TAG = "inspection_tool"
|
||||
const val CLASS_ATTR = "class"
|
||||
const val ENABLED_ATTR = "enabled"
|
||||
const val ENABLED_BY_DEFAULT_ATTR = "enabled_by_default"
|
||||
const val LEVEL_ATTR = "level"
|
||||
}
|
||||
}
|
||||
|
||||
class PyUnusedParameterInspectionMerger : PyUnusedSymbolInspectionMerger() {
|
||||
override fun getMergedToolName(): String = "PyUnusedParameterInspection"
|
||||
override val mergedSuppressId: String get() = "unused-parameter"
|
||||
}
|
||||
|
||||
class PyUnusedFunctionInspectionMerger : PyUnusedSymbolInspectionMerger() {
|
||||
override fun getMergedToolName(): String = "PyUnusedFunctionInspection"
|
||||
override val mergedSuppressId: String get() = "unused-function"
|
||||
}
|
||||
@@ -10,7 +10,9 @@ import com.jetbrains.python.inspections.PyPep8Inspection;
|
||||
import com.jetbrains.python.inspections.PySingleQuotedDocstringInspection;
|
||||
import com.jetbrains.python.inspections.PyStatementEffectInspection;
|
||||
import com.jetbrains.python.inspections.PyUnboundLocalVariableInspection;
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedFunctionInspection;
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedLocalInspection;
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedParameterInspection;
|
||||
import com.jetbrains.python.psi.PythonVisitorFilter;
|
||||
import com.jetbrains.python.validation.PyDocStringHighlightingAnnotator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -26,7 +28,8 @@ final class ConsoleVisitorFilter implements PythonVisitorFilter {
|
||||
//if we're in console
|
||||
if (PydevConsoleRunnerUtil.isInPydevConsole(file)) {
|
||||
//inspections
|
||||
if (visitorClass == PyUnusedLocalInspection.class || visitorClass == PyUnboundLocalVariableInspection.class ||
|
||||
if (visitorClass == PyUnusedLocalInspection.class || visitorClass == PyUnusedParameterInspection.class ||
|
||||
visitorClass == PyUnusedFunctionInspection.class || visitorClass == PyUnboundLocalVariableInspection.class ||
|
||||
visitorClass == PyStatementEffectInspection.class || visitorClass == PySingleQuotedDocstringInspection.class ||
|
||||
visitorClass == PyIncorrectDocstringInspection.class || visitorClass == PyMissingOrEmptyDocstringInspection.class ||
|
||||
visitorClass == PyMandatoryEncodingInspection.class || visitorClass == PyPep8Inspection.class ||
|
||||
|
||||
@@ -10,7 +10,9 @@ import com.jetbrains.python.inspections.PyPropertyDefinitionInspection;
|
||||
import com.jetbrains.python.inspections.PyShadowingBuiltinsInspection;
|
||||
import com.jetbrains.python.inspections.PyStatementEffectInspection;
|
||||
import com.jetbrains.python.inspections.PyTypeCheckerInspection;
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedFunctionInspection;
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedLocalInspection;
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedParameterInspection;
|
||||
import com.jetbrains.python.psi.PythonVisitorFilter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -20,6 +22,8 @@ public final class PyiVisitorFilter implements PythonVisitorFilter {
|
||||
|
||||
private static final @NotNull Set<Class<?>> disabledVisitors = ImmutableSet.of(
|
||||
PyUnusedLocalInspection.class,
|
||||
PyUnusedParameterInspection.class,
|
||||
PyUnusedFunctionInspection.class,
|
||||
PyStatementEffectInspection.class,
|
||||
PyCompatibilityInspection.class,
|
||||
PyMissingOrEmptyDocstringInspection.class,
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.inspections
|
||||
|
||||
import com.intellij.lang.annotation.HighlightSeverity
|
||||
import com.intellij.idea.TestFor
|
||||
import com.jetbrains.python.PythonFileType
|
||||
import com.jetbrains.python.fixtures.PyCodeInsightTestCase
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedFunctionInspection
|
||||
import org.intellij.lang.annotations.Language
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
@TestFor(issues = ["PY-9687"])
|
||||
class PyUnusedFunctionInspectionTest : PyCodeInsightTestCase() {
|
||||
|
||||
/** Asserts the exact set of unused-function warnings (descriptions) reported for [code]. */
|
||||
private fun doTest(@Language("Python") code: String, vararg expectedMessages: String) {
|
||||
myFixture.configureByText(PythonFileType.INSTANCE, code.trimIndent())
|
||||
myFixture.enableInspections(PyUnusedFunctionInspection())
|
||||
val actual = myFixture.doHighlighting()
|
||||
.filter { it.severity == HighlightSeverity.WEAK_WARNING }
|
||||
.map { it.description }
|
||||
.sorted()
|
||||
Assertions.assertEquals(expectedMessages.sorted(), actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `unused local function is reported`() {
|
||||
// The unused local variable 'a' belongs to PyUnusedLocal and is not enabled here.
|
||||
doTest("""
|
||||
def outer():
|
||||
a = 1
|
||||
def inner():
|
||||
return 1
|
||||
return a
|
||||
""", "Local function 'inner' is not used")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `used local function is not reported`() {
|
||||
doTest("""
|
||||
def outer():
|
||||
def inner():
|
||||
return 1
|
||||
return inner()
|
||||
""")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `noinspection unused-function suppresses the function`() {
|
||||
doTest("""
|
||||
def outer():
|
||||
# noinspection unused-function
|
||||
def inner():
|
||||
return 1
|
||||
return 0
|
||||
""")
|
||||
}
|
||||
}
|
||||
@@ -15,19 +15,25 @@
|
||||
*/
|
||||
package com.jetbrains.python.inspections;
|
||||
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.idea.TestFor;
|
||||
import com.jetbrains.python.fixtures.PyInspectionTestCase;
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedFunctionInspection;
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedLocalInspection;
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedParameterInspection;
|
||||
import com.jetbrains.python.psi.LanguageLevel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PyUnusedLocalInspectionTest extends PyInspectionTestCase {
|
||||
|
||||
public void testPy2() {
|
||||
final PyUnusedLocalInspection inspection = new PyUnusedLocalInspection();
|
||||
inspection.ignoreTupleUnpacking = false;
|
||||
inspection.ignoreLambdaParameters = false;
|
||||
runWithLanguageLevel(LanguageLevel.PYTHON27, () -> doTest(inspection));
|
||||
final PyUnusedParameterInspection parameterInspection = new PyUnusedParameterInspection();
|
||||
parameterInspection.ignoreLambdaParameters = false;
|
||||
runWithLanguageLevel(LanguageLevel.PYTHON27, () -> doTest(inspection, parameterInspection));
|
||||
}
|
||||
|
||||
public void testNonlocal() {
|
||||
@@ -149,7 +155,6 @@ public class PyUnusedLocalInspectionTest extends PyInspectionTestCase {
|
||||
public void testIgnoringVariablesStartingWithUnderscore() {
|
||||
final PyUnusedLocalInspection inspection = new PyUnusedLocalInspection();
|
||||
inspection.ignoreVariablesStartingWithUnderscore = true;
|
||||
inspection.ignoreLambdaParameters = false;
|
||||
inspection.ignoreLoopIterationVariables = false;
|
||||
inspection.ignoreTupleUnpacking = false;
|
||||
doTest(inspection);
|
||||
@@ -310,10 +315,21 @@ def test():
|
||||
return PyUnusedLocalInspection.class;
|
||||
}
|
||||
|
||||
// Parameter and function reporting now live in separate inspections; enable them too so the shared testData keeps matching.
|
||||
@NotNull
|
||||
@Override
|
||||
protected List<Class<? extends LocalInspectionTool>> getAdditionalInspectionClasses() {
|
||||
return List.of(PyUnusedParameterInspection.class, PyUnusedFunctionInspection.class);
|
||||
}
|
||||
|
||||
private void doTest(@NotNull PyUnusedLocalInspection inspection) {
|
||||
doTest(inspection, new PyUnusedParameterInspection());
|
||||
}
|
||||
|
||||
private void doTest(@NotNull PyUnusedLocalInspection inspection, @NotNull PyUnusedParameterInspection parameterInspection) {
|
||||
final String path = "inspections/PyUnusedLocalInspection/" + getTestName(true) + ".py";
|
||||
myFixture.configureByFile(path);
|
||||
myFixture.enableInspections(inspection);
|
||||
myFixture.enableInspections(inspection, parameterInspection, new PyUnusedFunctionInspection());
|
||||
myFixture.checkHighlighting(true, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.inspections
|
||||
|
||||
import com.intellij.lang.annotation.HighlightSeverity
|
||||
import com.intellij.idea.TestFor
|
||||
import com.jetbrains.python.PythonFileType
|
||||
import com.jetbrains.python.fixtures.PyCodeInsightTestCase
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedParameterInspection
|
||||
import org.intellij.lang.annotations.Language
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
@TestFor(issues = ["PY-9687"])
|
||||
class PyUnusedParameterInspectionTest : PyCodeInsightTestCase() {
|
||||
|
||||
/** Asserts the exact set of unused-parameter warnings (descriptions) reported for [code]. */
|
||||
private fun doTest(@Language("Python") code: String, vararg expectedMessages: String) {
|
||||
myFixture.configureByText(PythonFileType.INSTANCE, code.trimIndent())
|
||||
myFixture.enableInspections(PyUnusedParameterInspection())
|
||||
val actual = myFixture.doHighlighting()
|
||||
.filter { it.severity == HighlightSeverity.WEAK_WARNING }
|
||||
.map { it.description }
|
||||
.sorted()
|
||||
Assertions.assertEquals(expectedMessages.sorted(), actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `unused parameter is reported`() {
|
||||
// The unused local 'a' belongs to PyUnusedLocal and is not enabled here.
|
||||
doTest("""
|
||||
def f(x):
|
||||
a = 1
|
||||
""", "Parameter 'x' value is not used")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `self is not reported but a regular parameter is`() {
|
||||
doTest("""
|
||||
class A:
|
||||
def m(self, x):
|
||||
return 1
|
||||
""", "Parameter 'x' value is not used")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `lambda parameter is not reported`() {
|
||||
doTest("""
|
||||
f = lambda x: 1
|
||||
print(f)
|
||||
""")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `noinspection unused-parameter suppresses the parameter`() {
|
||||
doTest("""
|
||||
# noinspection unused-parameter
|
||||
def f(x):
|
||||
return 1
|
||||
""")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `legacy PyUnusedLocal does not suppress the parameter`() {
|
||||
// Clean break: PyUnusedLocal no longer silences parameters.
|
||||
doTest("""
|
||||
# noinspection PyUnusedLocal
|
||||
def f(x):
|
||||
return 1
|
||||
""", "Parameter 'x' value is not used")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.inspections
|
||||
|
||||
import com.intellij.codeInspection.ex.InspectionProfileImpl
|
||||
import com.intellij.codeInspection.ex.InspectionToolRegistrar
|
||||
import com.intellij.idea.TestFor
|
||||
import com.intellij.openapi.util.JDOMUtil
|
||||
import com.jetbrains.python.fixtures.PyTestCase
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedParameterInspection
|
||||
|
||||
/**
|
||||
* Verifies that profile settings from the former combined `PyUnusedLocalInspection` migrate to the inspections that PY-9687 split
|
||||
* it into, so users who had disabled or reconfigured it are not silently reset to defaults.
|
||||
*/
|
||||
@TestFor(issues = ["PY-9687"])
|
||||
class PyUnusedSymbolInspectionMergerTest : PyTestCase() {
|
||||
private lateinit var profile: InspectionProfileImpl
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
InspectionProfileImpl.INIT_INSPECTIONS = true
|
||||
profile = InspectionProfileImpl("Test", InspectionToolRegistrar.getInstance(), InspectionProfileImpl("base"))
|
||||
}
|
||||
|
||||
override fun tearDown() {
|
||||
try {
|
||||
InspectionProfileImpl.INIT_INSPECTIONS = false
|
||||
}
|
||||
finally {
|
||||
super.tearDown()
|
||||
}
|
||||
}
|
||||
|
||||
// A user who disabled the former combined inspection should not get the split-out inspections back, enabled, at their defaults.
|
||||
fun testDisabledStateMigratesToSplitInspections() {
|
||||
profile.readExternal(JDOMUtil.load("""
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Test" />
|
||||
<inspection_tool class="PyUnusedLocalInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
</profile>"""))
|
||||
assertFalse(profile.getToolsOrNull("PyUnusedParameterInspection", null)!!.isEnabled)
|
||||
assertFalse(profile.getToolsOrNull("PyUnusedFunctionInspection", null)!!.isEnabled)
|
||||
}
|
||||
|
||||
// The ignoreLambdaParameters option used to live on PyUnusedLocalInspection; it must carry over to the parameter inspection.
|
||||
fun testIgnoreLambdaParametersOptionMigrates() {
|
||||
profile.readExternal(JDOMUtil.load("""
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Test" />
|
||||
<inspection_tool class="PyUnusedLocalInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="ignoreLambdaParameters" value="false" />
|
||||
</inspection_tool>
|
||||
</profile>"""))
|
||||
val tool = profile.getToolsOrNull("PyUnusedParameterInspection", null)!!.tool.tool as PyUnusedParameterInspection
|
||||
assertFalse(tool.ignoreLambdaParameters)
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ import com.jetbrains.python.inspections.PyTypeCheckerInspection;
|
||||
import com.jetbrains.python.inspections.PyUnboundLocalVariableInspection;
|
||||
import com.jetbrains.python.inspections.PyUnusedImportsInspection;
|
||||
import com.jetbrains.python.inspections.unresolvedReference.PyUnresolvedReferencesInspection;
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedLocalInspection;
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedParameterInspection;
|
||||
import com.jetbrains.python.psi.PythonVisitorFilter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -110,7 +110,7 @@ public class PyiInspectionsTest extends PyTestCase {
|
||||
}
|
||||
|
||||
public void testPyiUnusedParameters() {
|
||||
doPyiTest(PyUnusedLocalInspection.class);
|
||||
doPyiTest(PyUnusedParameterInspection.class);
|
||||
}
|
||||
|
||||
public void testPyiStatementEffect() {
|
||||
|
||||
@@ -21,7 +21,7 @@ import com.jetbrains.python.PyQuickFixTestCase;
|
||||
import com.jetbrains.python.allure.Layers;
|
||||
import com.jetbrains.python.allure.Subsystems;
|
||||
import com.jetbrains.python.inspections.unresolvedReference.PyUnresolvedReferencesInspection;
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedLocalInspection;
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedParameterInspection;
|
||||
import com.jetbrains.python.psi.LanguageLevel;
|
||||
|
||||
@TestDataPath("$CONTENT_ROOT/../testData//quickFixes/AddFieldQuickFixTest/")
|
||||
@@ -52,16 +52,16 @@ public class PyAddFieldQuickFixTest extends PyQuickFixTestCase {
|
||||
}
|
||||
|
||||
public void testFromUnusedParameter() { // PY-1398
|
||||
doQuickFixTest(PyUnusedLocalInspection.class, "Add field 'foo' to class A");
|
||||
doQuickFixTest(PyUnusedParameterInspection.class, "Add field 'foo' to class A");
|
||||
}
|
||||
|
||||
// PY-14733
|
||||
public void testAddFieldInitializationInsideEmptyInit() {
|
||||
doQuickFixTest(PyUnusedLocalInspection.class, "Add field 'foo' to class A");
|
||||
doQuickFixTest(PyUnusedParameterInspection.class, "Add field 'foo' to class A");
|
||||
}
|
||||
|
||||
public void testFromUnusedParameterKeyword() { // PY-1602
|
||||
doQuickFixTest(PyUnusedLocalInspection.class, "Add field 'foo' to class A");
|
||||
doQuickFixTest(PyUnusedParameterInspection.class, "Add field 'foo' to class A");
|
||||
}
|
||||
|
||||
// PY-21284
|
||||
|
||||
@@ -8,7 +8,7 @@ import com.jetbrains.python.PyQuickFixTestCase;
|
||||
import com.jetbrains.python.allure.Layers;
|
||||
import com.jetbrains.python.allure.Subsystems;
|
||||
import com.jetbrains.python.documentation.docstrings.DocStringFormat;
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedLocalInspection;
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedParameterInspection;
|
||||
import com.jetbrains.python.psi.LanguageLevel;
|
||||
|
||||
@TestDataPath("$CONTENT_ROOT/../testData//quickFixes/PyRemoveParameterQuickFixTest/")
|
||||
@@ -17,26 +17,26 @@ import com.jetbrains.python.psi.LanguageLevel;
|
||||
public class PyRemoveParameterQuickFixTest extends PyQuickFixTestCase {
|
||||
|
||||
public void testParam() {
|
||||
doQuickFixTest(PyUnusedLocalInspection.class, PyPsiBundle.message("QFIX.NAME.remove.parameter"));
|
||||
doQuickFixTest(PyUnusedParameterInspection.class, PyPsiBundle.message("QFIX.NAME.remove.parameter"));
|
||||
}
|
||||
|
||||
public void testKwParam() {
|
||||
doQuickFixTest(PyUnusedLocalInspection.class, PyPsiBundle.message("QFIX.NAME.remove.parameter"));
|
||||
doQuickFixTest(PyUnusedParameterInspection.class, PyPsiBundle.message("QFIX.NAME.remove.parameter"));
|
||||
}
|
||||
|
||||
public void testDocstring() {
|
||||
runWithDocStringFormat(DocStringFormat.REST, () ->
|
||||
doQuickFixTest(PyUnusedLocalInspection.class, PyPsiBundle.message("QFIX.NAME.remove.parameter"))
|
||||
doQuickFixTest(PyUnusedParameterInspection.class, PyPsiBundle.message("QFIX.NAME.remove.parameter"))
|
||||
);
|
||||
}
|
||||
|
||||
public void testUsage() {
|
||||
doQuickFixTest(PyUnusedLocalInspection.class, PyPsiBundle.message("QFIX.NAME.remove.parameter"));
|
||||
doQuickFixTest(PyUnusedParameterInspection.class, PyPsiBundle.message("QFIX.NAME.remove.parameter"));
|
||||
}
|
||||
|
||||
public void testSingleStarTwoParam() {
|
||||
runWithDocStringFormat(DocStringFormat.REST, () ->
|
||||
doQuickFixTest(PyUnusedLocalInspection.class, PyPsiBundle.message("QFIX.NAME.remove.parameter"), LanguageLevel.PYTHON34)
|
||||
doQuickFixTest(PyUnusedParameterInspection.class, PyPsiBundle.message("QFIX.NAME.remove.parameter"), LanguageLevel.PYTHON34)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ public class PyRemoveParameterQuickFixTest extends PyQuickFixTestCase {
|
||||
LanguageLevel.PYTHON34,
|
||||
() -> {
|
||||
final String testFileName = getTestName(true);
|
||||
myFixture.enableInspections(PyUnusedLocalInspection.class);
|
||||
myFixture.enableInspections(PyUnusedParameterInspection.class);
|
||||
myFixture.configureByFile(testFileName + ".py");
|
||||
myFixture.checkHighlighting(true, false, false);
|
||||
final IntentionAction intentionAction = myFixture.getAvailableIntention(PyPsiBundle.message("QFIX.NAME.remove.parameter"));
|
||||
@@ -56,11 +56,11 @@ public class PyRemoveParameterQuickFixTest extends PyQuickFixTestCase {
|
||||
|
||||
// PY-22971
|
||||
public void testTopLevelOverloadsAndImplementation() {
|
||||
doQuickFixTest(PyUnusedLocalInspection.class, PyPsiBundle.message("QFIX.NAME.remove.parameter"), LanguageLevel.PYTHON35);
|
||||
doQuickFixTest(PyUnusedParameterInspection.class, PyPsiBundle.message("QFIX.NAME.remove.parameter"), LanguageLevel.PYTHON35);
|
||||
}
|
||||
|
||||
// PY-22971
|
||||
public void testOverloadsAndImplementationInClass() {
|
||||
doQuickFixTest(PyUnusedLocalInspection.class, PyPsiBundle.message("QFIX.NAME.remove.parameter"), LanguageLevel.PYTHON35);
|
||||
doQuickFixTest(PyUnusedParameterInspection.class, PyPsiBundle.message("QFIX.NAME.remove.parameter"), LanguageLevel.PYTHON35);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.jetbrains.python.PyQuickFixTestCase;
|
||||
import com.jetbrains.python.allure.Layers;
|
||||
import com.jetbrains.python.allure.Subsystems;
|
||||
import com.jetbrains.python.inspections.PyReturnFromInitInspection;
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedFunctionInspection;
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedLocalInspection;
|
||||
|
||||
@TestDataPath("$CONTENT_ROOT/../testData//quickFixes/PyRemoveStatementQuickFixTest/")
|
||||
@@ -37,7 +38,7 @@ public class PyRemoveStatementQuickFixTest extends PyQuickFixTestCase {
|
||||
}
|
||||
|
||||
public void testFunction() {
|
||||
doQuickFixTest(PyUnusedLocalInspection.class, PyPsiBundle.message("QFIX.NAME.remove.statement"));
|
||||
doQuickFixTest(PyUnusedFunctionInspection.class, PyPsiBundle.message("QFIX.NAME.remove.statement"));
|
||||
}
|
||||
|
||||
public void testVariable() {
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.intellij.idea.TestFor
|
||||
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
|
||||
import com.jetbrains.python.fixtures.PyTestCase
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedLocalInspection
|
||||
import com.jetbrains.python.inspections.unusedLocal.PyUnusedParameterInspection
|
||||
import com.jetbrains.python.testing.pyTestParametrized.PyTestParametrizedInspection
|
||||
|
||||
/**
|
||||
@@ -15,7 +16,8 @@ class PyTestFixtureAndParametrizedTest : PyTestCase() {
|
||||
const val testSubfolder = "/testCompletion"
|
||||
fun testInspectionStatic(fixture: CodeInsightTestFixture) {
|
||||
fixture.configureByFile("test_for_inspection_test.py")
|
||||
fixture.enableInspections(PyUnusedLocalInspection::class.java, PyTestParametrizedInspection::class.java)
|
||||
fixture.enableInspections(PyUnusedLocalInspection::class.java, PyUnusedParameterInspection::class.java,
|
||||
PyTestParametrizedInspection::class.java)
|
||||
fixture.checkHighlighting(true, false, true)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user