diff --git a/python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java b/python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java index 4ee578511eec..8b2d0ec7dac7 100644 --- a/python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java @@ -27,15 +27,14 @@ import com.intellij.openapi.util.JDOMExternalizableStringList; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiElementVisitor; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiReference; +import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.QualifiedName; +import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyNames; +import com.jetbrains.python.inspections.quickfix.PyRenameElementQuickFix; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyBuiltinCache; import com.jetbrains.python.psi.types.PyClassType; @@ -325,5 +324,35 @@ public class PyCompatibilityInspection extends PyInspection { } } } + + @Override + public void visitPyTargetExpression(PyTargetExpression node) { + super.visitPyTargetExpression(node); + warnAboutAsyncAndAwaitInPy35AndPy36(node); + } + + @Override + public void visitPyClass(PyClass node) { + super.visitPyClass(node); + warnAboutAsyncAndAwaitInPy35AndPy36(node); + } + + @Override + public void visitPyFunction(PyFunction node) { + super.visitPyFunction(node); + warnAboutAsyncAndAwaitInPy35AndPy36(node); + } + + private void warnAboutAsyncAndAwaitInPy35AndPy36(@NotNull PsiNameIdentifierOwner nameIdentifierOwner) { + final PsiElement nameIdentifier = nameIdentifierOwner.getNameIdentifier(); + + if (nameIdentifier != null && ArrayUtil.contains(nameIdentifierOwner.getName(), PyNames.AWAIT, PyNames.ASYNC)) { + registerOnFirstMatchingVersion(level -> LanguageLevel.PYTHON35.equals(level) || LanguageLevel.PYTHON36.equals(level), + "'async' and 'await' are not recommended to be used as variable, class, function or module names. " + + "They will become proper keywords in Python 3.7.", + nameIdentifier, + new PyRenameElementQuickFix()); + } + } } } \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/warningAboutAsyncAndAwaitInPy35.py b/python/testData/inspections/PyCompatibilityInspection/warningAboutAsyncAndAwaitInPy35.py new file mode 100644 index 000000000000..eea16c40ef25 --- /dev/null +++ b/python/testData/inspections/PyCompatibilityInspection/warningAboutAsyncAndAwaitInPy35.py @@ -0,0 +1,14 @@ +class async(object): + pass + +class await(object): + pass + +def async(): + pass + +def await(): + pass + +async = 1 +await = 2 \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/warningAboutAsyncAndAwaitInPy36.py b/python/testData/inspections/PyCompatibilityInspection/warningAboutAsyncAndAwaitInPy36.py new file mode 100644 index 000000000000..eea16c40ef25 --- /dev/null +++ b/python/testData/inspections/PyCompatibilityInspection/warningAboutAsyncAndAwaitInPy36.py @@ -0,0 +1,14 @@ +class async(object): + pass + +class await(object): + pass + +def async(): + pass + +def await(): + pass + +async = 1 +await = 2 \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncClassInPy35.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncClassInPy35.py new file mode 100644 index 000000000000..bc25733ddf5d --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncClassInPy35.py @@ -0,0 +1,2 @@ +class async(object): + pass \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncClassInPy35_after.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncClassInPy35_after.py new file mode 100644 index 000000000000..1a98a9cfc6c4 --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncClassInPy35_after.py @@ -0,0 +1,2 @@ +class a(object): + pass \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncClassInPy36.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncClassInPy36.py new file mode 100644 index 000000000000..bc25733ddf5d --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncClassInPy36.py @@ -0,0 +1,2 @@ +class async(object): + pass \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncClassInPy36_after.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncClassInPy36_after.py new file mode 100644 index 000000000000..1a98a9cfc6c4 --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncClassInPy36_after.py @@ -0,0 +1,2 @@ +class a(object): + pass \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncFunctionInPy35.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncFunctionInPy35.py new file mode 100644 index 000000000000..f48d631547da --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncFunctionInPy35.py @@ -0,0 +1,2 @@ +def async(): + pass \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncFunctionInPy35_after.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncFunctionInPy35_after.py new file mode 100644 index 000000000000..690f3c163030 --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncFunctionInPy35_after.py @@ -0,0 +1,2 @@ +def a(): + pass \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncFunctionInPy36.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncFunctionInPy36.py new file mode 100644 index 000000000000..f48d631547da --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncFunctionInPy36.py @@ -0,0 +1,2 @@ +def async(): + pass \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncFunctionInPy36_after.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncFunctionInPy36_after.py new file mode 100644 index 000000000000..690f3c163030 --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncFunctionInPy36_after.py @@ -0,0 +1,2 @@ +def a(): + pass \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncVariableInPy35.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncVariableInPy35.py new file mode 100644 index 000000000000..96bae926eb40 --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncVariableInPy35.py @@ -0,0 +1 @@ +async = 1 \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncVariableInPy35_after.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncVariableInPy35_after.py new file mode 100644 index 000000000000..d25d49e0ffc3 --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncVariableInPy35_after.py @@ -0,0 +1 @@ +a = 1 \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncVariableInPy36.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncVariableInPy36.py new file mode 100644 index 000000000000..96bae926eb40 --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncVariableInPy36.py @@ -0,0 +1 @@ +async = 1 \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncVariableInPy36_after.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncVariableInPy36_after.py new file mode 100644 index 000000000000..d25d49e0ffc3 --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAsyncVariableInPy36_after.py @@ -0,0 +1 @@ +a = 1 \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitClassInPy35.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitClassInPy35.py new file mode 100644 index 000000000000..c531a434721e --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitClassInPy35.py @@ -0,0 +1,2 @@ +class await(object): + pass \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitClassInPy35_after.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitClassInPy35_after.py new file mode 100644 index 000000000000..1a98a9cfc6c4 --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitClassInPy35_after.py @@ -0,0 +1,2 @@ +class a(object): + pass \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitClassInPy36.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitClassInPy36.py new file mode 100644 index 000000000000..c531a434721e --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitClassInPy36.py @@ -0,0 +1,2 @@ +class await(object): + pass \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitClassInPy36_after.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitClassInPy36_after.py new file mode 100644 index 000000000000..1a98a9cfc6c4 --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitClassInPy36_after.py @@ -0,0 +1,2 @@ +class a(object): + pass \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitFunctionInPy35.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitFunctionInPy35.py new file mode 100644 index 000000000000..c1ef9d6ccfae --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitFunctionInPy35.py @@ -0,0 +1,2 @@ +def await(): + pass \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitFunctionInPy35_after.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitFunctionInPy35_after.py new file mode 100644 index 000000000000..690f3c163030 --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitFunctionInPy35_after.py @@ -0,0 +1,2 @@ +def a(): + pass \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitFunctionInPy36.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitFunctionInPy36.py new file mode 100644 index 000000000000..c1ef9d6ccfae --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitFunctionInPy36.py @@ -0,0 +1,2 @@ +def await(): + pass \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitFunctionInPy36_after.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitFunctionInPy36_after.py new file mode 100644 index 000000000000..690f3c163030 --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitFunctionInPy36_after.py @@ -0,0 +1,2 @@ +def a(): + pass \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitVariableInPy35.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitVariableInPy35.py new file mode 100644 index 000000000000..1a28415ce838 --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitVariableInPy35.py @@ -0,0 +1 @@ +await = 1 \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitVariableInPy35_after.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitVariableInPy35_after.py new file mode 100644 index 000000000000..d25d49e0ffc3 --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitVariableInPy35_after.py @@ -0,0 +1 @@ +a = 1 \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitVariableInPy36.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitVariableInPy36.py new file mode 100644 index 000000000000..1a28415ce838 --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitVariableInPy36.py @@ -0,0 +1 @@ +await = 1 \ No newline at end of file diff --git a/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitVariableInPy36_after.py b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitVariableInPy36_after.py new file mode 100644 index 000000000000..d25d49e0ffc3 --- /dev/null +++ b/python/testData/quickFixes/RenameElementQuickFixTest/renameAwaitVariableInPy36_after.py @@ -0,0 +1 @@ +a = 1 \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/PyCompatibilityInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyCompatibilityInspectionTest.java index 4bc87459c36f..7afe19f1f695 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyCompatibilityInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyCompatibilityInspectionTest.java @@ -209,6 +209,16 @@ public class PyCompatibilityInspectionTest extends PyTestCase { doTest(LanguageLevel.PYTHON36); } + // PY-16098 + public void testWarningAboutAsyncAndAwaitInPy35() { + doTest(LanguageLevel.PYTHON35); + } + + // PY-16098 + public void testWarningAboutAsyncAndAwaitInPy36() { + doTest(LanguageLevel.PYTHON36); + } + private void doTest(@NotNull LanguageLevel level) { runWithLanguageLevel(level, this::doTest); } diff --git a/python/testSrc/com/jetbrains/python/quickFixes/RenameElementQuickFixTest.java b/python/testSrc/com/jetbrains/python/quickFixes/RenameElementQuickFixTest.java index 5a63b49b66e6..66a01ae20e1f 100644 --- a/python/testSrc/com/jetbrains/python/quickFixes/RenameElementQuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/quickFixes/RenameElementQuickFixTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -17,6 +17,7 @@ package com.jetbrains.python.quickFixes; import com.intellij.testFramework.TestDataPath; import com.jetbrains.python.PyQuickFixTestCase; +import com.jetbrains.python.inspections.PyCompatibilityInspection; import com.jetbrains.python.inspections.PyPep8NamingInspection; import com.jetbrains.python.inspections.PyProtectedMemberInspection; import com.jetbrains.python.inspections.PyShadowingBuiltinsInspection; @@ -47,4 +48,63 @@ public class RenameElementQuickFixTest extends PyQuickFixTestCase { doQuickFixTest(PyShadowingBuiltinsInspection.class, "Rename element"); } + // PY-16098 + public void testRenameAsyncClassInPy35() { + doQuickFixTest(PyCompatibilityInspection.class, "Rename element"); + } + + // PY-16098 + public void testRenameAsyncClassInPy36() { + doQuickFixTest(PyCompatibilityInspection.class, "Rename element"); + } + + // PY-16098 + public void testRenameAwaitClassInPy35() { + doQuickFixTest(PyCompatibilityInspection.class, "Rename element"); + } + + // PY-16098 + public void testRenameAwaitClassInPy36() { + doQuickFixTest(PyCompatibilityInspection.class, "Rename element"); + } + + // PY-16098 + public void testRenameAsyncFunctionInPy35() { + doQuickFixTest(PyCompatibilityInspection.class, "Rename element"); + } + + // PY-16098 + public void testRenameAsyncFunctionInPy36() { + doQuickFixTest(PyCompatibilityInspection.class, "Rename element"); + } + + // PY-16098 + public void testRenameAwaitFunctionInPy35() { + doQuickFixTest(PyCompatibilityInspection.class, "Rename element"); + } + + // PY-16098 + public void testRenameAwaitFunctionInPy36() { + doQuickFixTest(PyCompatibilityInspection.class, "Rename element"); + } + + // PY-16098 + public void testRenameAsyncVariableInPy35() { + doQuickFixTest(PyCompatibilityInspection.class, "Rename element"); + } + + // PY-16098 + public void testRenameAsyncVariableInPy36() { + doQuickFixTest(PyCompatibilityInspection.class, "Rename element"); + } + + // PY-16098 + public void testRenameAwaitVariableInPy35() { + doQuickFixTest(PyCompatibilityInspection.class, "Rename element"); + } + + // PY-16098 + public void testRenameAwaitVariableInPy36() { + doQuickFixTest(PyCompatibilityInspection.class, "Rename element"); + } }