diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties index 4e23df221842..a747d89160b7 100644 --- a/python/src/com/jetbrains/python/PyBundle.properties +++ b/python/src/com/jetbrains/python/PyBundle.properties @@ -328,6 +328,7 @@ INSP.empty.docstring=Empty docstring # PyStatementEffectInspection INSP.NAME.statement.effect=Statement has no effect +INSP.NAME.statement.message=Statement seems to have no effect # PySimplifyBooleanCheckInspection INSP.NAME.check.can.be.simplified=Boolean variable check can be simplified diff --git a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java index d36d71d6c5e4..6b1fc574f899 100644 --- a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java +++ b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java @@ -97,7 +97,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i return describeDecorators(cls, LSame2, ", ", LSame1).add(describeClass(cls, LSame2, false, false)).toString() + "\n" + summary; } else if (element instanceof PyTargetExpression || element instanceof PyNamedParameter) { - return describeExpression((PyExpression)element, originalElement); + return describeExpression((PyExpression)element); } return null; } @@ -126,7 +126,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i } @Nullable - private static String describeExpression(PyExpression expr, PsiElement originalElement) { + private static String describeExpression(PyExpression expr) { final String name = expr.getName(); if (name != null) { StringBuilder result = new StringBuilder((expr instanceof PyNamedParameter) ? "parameter" : "variable"); @@ -138,9 +138,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i result.append(String.format(" \"%s\"", function.getName())); } } - if (originalElement instanceof PyExpression && originalElement.isValid()) { - result.append("\n").append(describeExpressionType((PyExpression)originalElement)); - } + result.append("\n").append(describeExpressionType(expr)); return result.toString(); } return null; diff --git a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java index 7157791158ed..264d2c7efa0f 100644 --- a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java @@ -62,10 +62,15 @@ public class PyStatementEffectInspection extends PyInspection { return; } } - if (checkStringLiteral(expression)) + if (checkStringLiteral(expression)) { return; - registerProblem(expression, "Statement seems to have no effect", - new StatementEffectIntroduceVariableQuickFix()); + } + if (expression instanceof PyReferenceExpression && ((PyReferenceExpression)expression).getQualifier() == null) { + registerProblem(expression, PyBundle.message("INSP.NAME.statement.message")); + } + else { + registerProblem(expression, PyBundle.message("INSP.NAME.statement.message"), new StatementEffectIntroduceVariableQuickFix()); + } } private boolean checkStringLiteral(PyExpression expression) { diff --git a/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java b/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java index 6c9e59593682..07667e9cf957 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java +++ b/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java @@ -266,8 +266,7 @@ public class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor { if (paramList != null && paramList.getParent() instanceof PyFunction) { final PyFunction func = (PyFunction) paramList.getParent(); containingClass = func.getContainingClass(); - final String funcName = func.getName(); - if (PyNames.INIT.equals(funcName) && containingClass != null) { + if (PyNames.INIT.equals(func.getName()) && containingClass != null) { if (!namedParameter.isKeywordContainer() && !namedParameter.isPositionalContainer()) { mayBeField = true; } @@ -276,9 +275,6 @@ public class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor { continue; } if (func.asMethod() != null) { - if (funcName != null && isSpecialName(funcName) && !PyNames.INIT.equals(funcName) && !PyNames.NEW.equals(funcName)) { - continue; - } Boolean isEmpty = emptyFunctions.get(func); if (isEmpty == null) { isEmpty = isEmptyFunction(func); @@ -313,11 +309,6 @@ public class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor { } } - private static boolean isSpecialName(@NotNull String name) { - final String dunder = "__"; - return name.startsWith(dunder) && name.endsWith(dunder) && name.length() > (dunder.length() * 2); - } - private boolean isRangeIteration(PyForStatement forStatement) { final PyExpression source = forStatement.getForPart().getSource(); if (!(source instanceof PyCallExpression)) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java index 54b1055e8a23..84a1bd255be6 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java @@ -178,9 +178,16 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl ourPossibleFields = ImmutableSet.of("__name__", "__file__", "__path__", "__doc__", "__dict__"); + protected static ImmutableSet ourPossibleFields = ImmutableSet.of("__name__", "__file__", "__path__", "__doc__", "__dict__", "__package__"); public PyModuleType(@NotNull PyFile source) { this(source, null); diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/dunderPackage.py b/python/testData/inspections/PyUnresolvedReferencesInspection/dunderPackage.py new file mode 100644 index 000000000000..5439e8997e21 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/dunderPackage.py @@ -0,0 +1 @@ +__package__ #pass \ No newline at end of file diff --git a/python/testData/inspections/PyUnusedLocalVariableInspection/test.py b/python/testData/inspections/PyUnusedLocalVariableInspection/test.py index 087e5f3f2bb2..ec747ac101f2 100644 --- a/python/testData/inspections/PyUnusedLocalVariableInspection/test.py +++ b/python/testData/inspections/PyUnusedLocalVariableInspection/test.py @@ -286,9 +286,3 @@ class C: # PY-7126 def test_unused_empty_function(x): pass - - -# PY-7178 -class C(object): - def __getattr__(self, name): # pass - return 42 diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java index 10a1e5e9364a..efd5d0eb1606 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java @@ -165,6 +165,11 @@ public class PyUnresolvedReferencesInspectionTest extends PyTestCase { doTest(); } + // PY-7043 + public void testDunderPackage() { + doTest(); + } + private void doTest() { myFixture.configureByFile(TEST_DIRECTORY + getTestName(true) + ".py"); myFixture.enableInspections(PyUnresolvedReferencesInspection.class);