eric7/Plugins/CheckerPlugins/CodeStyleChecker/Miscellaneous/MiscellaneousChecker.py

branch
eric7
changeset 8759
7efebdfa5dc2
parent 8312
800c432b34c8
child 8881
54e42bc2437a
--- a/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Miscellaneous/MiscellaneousChecker.py	Tue Nov 02 18:02:00 2021 +0100
+++ b/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Miscellaneous/MiscellaneousChecker.py	Wed Nov 03 19:34:56 2021 +0100
@@ -55,10 +55,9 @@
         "M131", "M132",
         
         ## Comprehensions
-        "M181", "M182", "M183", "M184",
-        "M185", "M186", "M187",
-        "M191", "M192", "M193",
-        "M195", "M196", "M197", "M198",
+        "M181", "M182", "M183", "M184", "M185", "M186", "M187", "M188",
+        "M189",
+        "M191", "M192", "M193", "M195", "M196", "M197", "M198",
         
         ## Dictionaries with sorted keys
         "M201",
@@ -173,7 +172,8 @@
             (self.__checkCopyright, ("M111", "M112")),
             (self.__checkBuiltins, ("M131", "M132")),
             (self.__checkComprehensions, ("M181", "M182", "M183", "M184",
-                                          "M185", "M186", "M187",
+                                          "M185", "M186", "M187", "M188",
+                                          "M189",
                                           "M191", "M192", "M193",
                                           "M195", "M196", "M197", "M198")),
             (self.__checkDictWithSortedKeys, ("M201",)),
@@ -682,6 +682,7 @@
         for node in ast.walk(self.__tree):
             if isinstance(node, ast.Call) and isinstance(node.func, ast.Name):
                 nArgs = len(node.args)
+                nKwArgs = len(node.keywords)
                 
                 if (
                     nArgs == 1 and
@@ -696,21 +697,25 @@
 
                 elif (
                     nArgs == 1 and
-                    isinstance(node.args[0], ast.GeneratorExp) and
+                    isinstance(node.args[0],
+                               (ast.GeneratorExp, ast.ListComp)) and
                     isinstance(node.args[0].elt, ast.Tuple) and
                     len(node.args[0].elt.elts) == 2 and
                     node.func.id == "dict"
                 ):
-                    self.__error(node.lineno - 1, node.col_offset, "M183")
+                    if isinstance(node.args[0], ast.GeneratorExp):
+                        errorCode = "M183"
+                    else:
+                        errorCode = "M185"
+                    self.__error(node.lineno - 1, node.col_offset, errorCode)
                 
                 elif (
                     nArgs == 1 and
                     isinstance(node.args[0], ast.ListComp) and
-                    node.func.id in ('list', 'set', 'dict')
+                    node.func.id in ('list', 'set')
                 ):
                     errorCode = {
                         'list': 'M195',
-                        'dict': 'M185',
                         'set': 'M184',
                     }[node.func.id]
                     self.__error(node.lineno - 1, node.col_offset, errorCode)
@@ -743,32 +748,109 @@
                     self.__error(node.lineno - 1, node.col_offset, errorCode,
                                  type(node.args[0]).__name__.lower(),
                                  node.func.id)
-
-                elif (
-                    nArgs == 1 and
-                    isinstance(node.args[0], ast.ListComp) and
-                    node.func.id in ('all', 'any', 'enumerate', 'frozenset',
-                                     'max', 'min', 'sorted', 'sum', 'tuple',)
-                ):
-                    self.__error(node.lineno - 1, node.col_offset, "M187",
-                                 node.func.id)
                 
                 elif (
                     nArgs == 0 and
                     not any(isinstance(a, ast.Starred) for a in node.args) and
                     not any(k.arg is None for k in node.keywords) and
-                    node.func.id in ("tuple", "list", "dict")
+                    node.func.id == "dict"
+                ) or (
+                    nArgs == 0 and
+                    nKwArgs == 0 and
+                    node.func.id in ("tuple", "list")
                 ):
                     self.__error(node.lineno - 1, node.col_offset, "M186",
                                  node.func.id)
                 
-                elif isinstance(node, ast.Compare) and (
-                    len(node.ops) == 1 and
-                    isinstance(node.ops[0], ast.In) and
-                    len(node.comparators) == 1 and
-                    isinstance(node.comparators[0], ast.ListComp)
+                elif (
+                    node.func.id in {"list", "reversed"} and
+                    nArgs > 0 and
+                    isinstance(node.args[0], ast.Call) and
+                    isinstance(node.args[0].func, ast.Name) and
+                    node.args[0].func.id == "sorted"
                 ):
-                    self.__error(node.lineno - 1, node.col_offset, "M196")
+                    if node.func.id == "reversed":
+                        reverseFlagValue = False
+                        for kw in node.args[0].keywords:
+                            if kw.arg != "reverse":
+                                continue
+                            if isinstance(kw.value, ast.NameConstant):
+                                reverseFlagValue = kw.value.value
+                            elif isinstance(kw.value, ast.Num):
+                                reverseFlagValue = bool(kw.value.n)
+                            else:
+                                # Complex value
+                                reverseFlagValue = None
+
+                        if reverseFlagValue is None:
+                            self.__error(node.lineno - 1, node.col_offset,
+                                         "M187a", node.func.id,
+                                         node.args[0].func.id)
+                        else:
+                            self.__error(node.lineno - 1, node.col_offset,
+                                         "M187b", node.func.id,
+                                         node.args[0].func.id,
+                                         not reverseFlagValue)
+                    else:
+                        self.__error(node.lineno - 1, node.col_offset,
+                                     "M187c", node.func.id,
+                                     node.args[0].func.id)
+                
+                elif (
+                    nArgs > 0 and
+                    isinstance(node.args[0], ast.Call) and
+                    isinstance(node.args[0].func, ast.Name) and
+                    (
+                        (
+                            node.func.id in {"set", "sorted"} and
+                            node.args[0].func.id in {
+                                "list", "reversed", "sorted", "tuple"}
+                        ) or (
+                            node.func.id in {"list", "tuple"} and
+                            node.args[0].func.id in {"list", "tuple"}
+                        ) or (
+                            node.func.id == "set" and
+                            node.args[0].func.id == "set"
+                        )
+                    )
+                ):
+                    self.__error(node.lineno - 1, node.col_offset, "M188",
+                                 node.args[0].func.id, node.func.id)
+                
+                elif (
+                    node.func.id in {"reversed", "set", "sorted"} and
+                    nArgs > 0 and
+                    isinstance(node.args[0], ast.Subscript) and
+                    isinstance(node.args[0].slice, ast.Slice) and
+                    node.args[0].slice.lower is None and
+                    node.args[0].slice.upper is None and
+                    isinstance(node.args[0].slice.step, ast.UnaryOp) and
+                    isinstance(node.args[0].slice.step.op, ast.USub) and
+                    isinstance(node.args[0].slice.step.operand, ast.Num) and
+                    node.args[0].slice.step.operand.n == 1
+                ):
+                    self.__error(node.lineno - 1, node.col_offset,
+                                 "M189", node.func.id)
+                
+                elif (
+                    isinstance(node, (ast.ListComp, ast.SetComp)) and (
+                        len(node.generators) == 1 and
+                        not node.generators[0].ifs and
+                        not node.generators[0].is_async and (
+                            isinstance(node.elt, ast.Name) and
+                            isinstance(node.generators[0].target, ast.Name) and
+                            node.elt.id == node.generators[0].target.id
+                        )
+                    )
+                ):
+                    compType = {
+                        ast.DictComp: "dict",
+                        ast.ListComp: "list",
+                        ast.SetComp: "set",
+                    }[node.__class__]
+                    
+                    self.__error(node.lineno - 1, node.col_offset,
+                                 "M196", compType)
     
     def __checkMutableDefault(self):
         """

eric ide

mercurial