diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index af292f1ebb78..775af1e2ffec 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -444,27 +444,30 @@ public class PyUtil { } /** - * For cases when a function is decorated many decorators, and the innermost is a built-in decorator: + * When a function is decorated many decorators, finds the deepest builtin decorator: *
    * @foo
    * @classmethod # <-- that's it
+   * @bar
    * def moo(cls):
    *   pass
    * 
* @param node the allegedly decorated function - * @return name of the only built-in decorator, or null (even if there are multiple or non-built-in decorators!) + * @return name of the built-in decorator, or null (even if there are non-built-in decorators). */ public static @Nullable - String getImmediateBuiltinDecorator(@NotNull final PyFunction node) { + String getDeepestBuiltinDecorator(@NotNull final PyFunction node) { PyDecoratorList decolist = node.getDecoratorList(); if (decolist != null) { PyDecorator[] decos = decolist.getDecorators(); if (decos.length > 0) { - PyDecorator deco = decos[decos.length - 1]; - String deconame = deco.getName(); - if (deco.isBuiltin()) { - return deconame; + for (int i = decos.length - 1; i >= 0; i -= 1) { + PyDecorator deco = decos[i]; + String deconame = deco.getName(); + if (deco.isBuiltin()) { + return deconame; + } } } } @@ -480,7 +483,7 @@ public class PyUtil { @NotNull public static Set detectDecorationsAndWrappersOf(PyFunction function) { Set flags = EnumSet.noneOf(PyFunction.Flag.class); - String deconame = getImmediateBuiltinDecorator(function); + String deconame = getDeepestBuiltinDecorator(function); if (PyNames.CLASSMETHOD.equals(deconame)) { flags.add(CLASSMETHOD); } diff --git a/python/testData/inspections/PyMethodParametersInspection/expected.xml b/python/testData/inspections/PyMethodParametersInspection/expected.xml index 3ae541af0bc5..bcdb702c404c 100644 --- a/python/testData/inspections/PyMethodParametersInspection/expected.xml +++ b/python/testData/inspections/PyMethodParametersInspection/expected.xml @@ -2,24 +2,19 @@ first_arg.py - 9 + 13 Usually first parameter of a method is named 'self' first_arg.py - 12 + 16 Method must have a first parameter, usually called 'self' first_arg.py - 15 + 19 First parameter of a non-static method must not be a tuple - - first_arg.py - 21 - Usually first parameter of such methods is named 'cls' - first_arg.py 25 @@ -27,17 +22,32 @@ first_arg.py - 38 + 29 + Usually first parameter of such methods is named 'cls' + + + first_arg.py + 34 + Usually first parameter of such methods is named 'cls' + + + first_arg.py + 39 + Usually first parameter of such methods is named 'cls' + + + first_arg.py + 62 Usually first parameter of a method is named 'self' first_arg.py - 41 + 65 Usually first parameter of such methods is named 'cls' first_arg.py - 44 + 68 Usually first parameter of such methods is named 'cls'