diff --git a/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspection.java b/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspection.java index 5c7d6751e9c8..e2ee86d6b007 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspection.java @@ -35,22 +35,24 @@ public class PyUnusedLocalInspection extends PyInspection { public boolean ignoreTupleUnpacking = true; public boolean ignoreLambdaParameters = true; public boolean ignoreLoopIterationVariables = true; + public boolean ignoreVariablesStartingWithUnderscore = true; + @Override @NotNull @Nls public String getDisplayName() { return PyBundle.message("INSP.NAME.unused"); } + @Override @NotNull - public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, - final boolean isOnTheFly, - @NotNull LocalInspectionToolSession session) { + public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly, @NotNull LocalInspectionToolSession session) { final PyUnusedLocalInspectionVisitor visitor = new PyUnusedLocalInspectionVisitor(holder, session, ignoreTupleUnpacking, ignoreLambdaParameters, - ignoreLoopIterationVariables); + ignoreLoopIterationVariables, + ignoreVariablesStartingWithUnderscore); // 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); if (existingVisitor == null) { @@ -70,10 +72,11 @@ public class PyUnusedLocalInspection extends PyInspection { @Override public JComponent createOptionsPanel() { - MultipleCheckboxOptionsPanel panel = new MultipleCheckboxOptionsPanel(this); + final MultipleCheckboxOptionsPanel panel = new MultipleCheckboxOptionsPanel(this); panel.addCheckbox("Ignore variables used in tuple unpacking", "ignoreTupleUnpacking"); panel.addCheckbox("Ignore lambda parameters", "ignoreLambdaParameters"); panel.addCheckbox("Ignore range iteration variables", "ignoreLoopIterationVariables"); + panel.addCheckbox("Ignore variables starting with '_'", "ignoreVariablesStartingWithUnderscore"); return panel; } } diff --git a/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java b/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java index 704bd1aea395..e095cdd34044 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java +++ b/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java @@ -62,6 +62,7 @@ public class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor { private final boolean myIgnoreTupleUnpacking; private final boolean myIgnoreLambdaParameters; private final boolean myIgnoreRangeIterationVariables; + private final boolean myIgnoreVariablesStartingWithUnderscore; private final HashSet myUnusedElements; private final HashSet myUsedElements; @@ -69,11 +70,13 @@ public class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor { @NotNull LocalInspectionToolSession session, boolean ignoreTupleUnpacking, boolean ignoreLambdaParameters, - boolean ignoreRangeIterationVariables) { + boolean ignoreRangeIterationVariables, + boolean ignoreVariablesStartingWithUnderscore) { super(holder, session); myIgnoreTupleUnpacking = ignoreTupleUnpacking; myIgnoreLambdaParameters = ignoreLambdaParameters; myIgnoreRangeIterationVariables = ignoreRangeIterationVariables; + myIgnoreVariablesStartingWithUnderscore = ignoreVariablesStartingWithUnderscore; myUnusedElements = new HashSet<>(); myUsedElements = new HashSet<>(); } @@ -395,7 +398,7 @@ public class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor { ProblemHighlightType.LIKE_UNUSED_SYMBOL, null, new ReplaceWithWildCard()); } } - else { + else if (!myIgnoreVariablesStartingWithUnderscore || !name.startsWith(PyNames.UNDERSCORE)) { registerWarning(element, PyBundle.message("INSP.unused.locals.local.variable.isnot.used", name), new PyRemoveStatementQuickFix()); } } diff --git a/python/testData/inspections/PyUnusedLocalInspection/underscorePrefixed.py b/python/testData/inspections/PyUnusedLocalInspection/underscorePrefixed.py index d48832ae25cc..7de162bc3939 100644 --- a/python/testData/inspections/PyUnusedLocalInspection/underscorePrefixed.py +++ b/python/testData/inspections/PyUnusedLocalInspection/underscorePrefixed.py @@ -1,5 +1,5 @@ def foo(): - l = [42 for _a in xrange(100)] + l = [42 for _a in xrange(100)] print(l) diff --git a/python/testData/inspections/PyUnusedLocalInspection/variableStartingWithUnderscore.py b/python/testData/inspections/PyUnusedLocalInspection/variableStartingWithUnderscore.py new file mode 100644 index 000000000000..a1bb44308514 --- /dev/null +++ b/python/testData/inspections/PyUnusedLocalInspection/variableStartingWithUnderscore.py @@ -0,0 +1,2 @@ +def foo(): + _var = 1 \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnusedLocalInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnusedLocalInspectionTest.java index 2a912b8ee335..f0cb7277962c 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnusedLocalInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnusedLocalInspectionTest.java @@ -87,6 +87,7 @@ public class PyUnusedLocalInspectionTest extends PyInspectionTestCase { } // PY-3996 + // PY-27435 public void testUnderscorePrefixed() { doTest(); } @@ -101,6 +102,13 @@ public class PyUnusedLocalInspectionTest extends PyInspectionTestCase { runWithLanguageLevel(LanguageLevel.PYTHON37, this::doTest); } + // PY-27435 + public void testVariableStartingWithUnderscore() { + final PyUnusedLocalInspection inspection = new PyUnusedLocalInspection(); + inspection.ignoreVariablesStartingWithUnderscore = false; + doTest(inspection); + } + @NotNull @Override protected Class getInspectionClass() {