Plugins/CheckerPlugins/SyntaxChecker/pyflakes/checker.py

changeset 6353
6a0f3abd6878
parent 6048
82ad8ec9548c
child 6645
ad476851d7e0
equal deleted inserted replaced
6352:4bdc6503df81 6353:6a0f3abd6878
10 10
11 Implement the central Checker class. 11 Implement the central Checker class.
12 Also, it models the Bindings and Scopes. 12 Also, it models the Bindings and Scopes.
13 """ 13 """
14 import __future__ 14 import __future__
15 import ast
15 import doctest 16 import doctest
16 import os 17 import os
17 import sys 18 import sys
18 19
19 PY2 = sys.version_info < (3, 0) 20 PY2 = sys.version_info < (3, 0)
20 PY32 = sys.version_info < (3, 3) # Python 2.5 to 3.2 21 PY34 = sys.version_info < (3, 5) # Python 2.7 to 3.4
21 PY33 = sys.version_info < (3, 4) # Python 2.5 to 3.3
22 PY34 = sys.version_info < (3, 5) # Python 2.5 to 3.4
23 try: 22 try:
24 sys.pypy_version_info 23 sys.pypy_version_info
25 PYPY = True 24 PYPY = True
26 except AttributeError: 25 except AttributeError:
27 PYPY = False 26 PYPY = False
28 27
29 builtin_vars = dir(__import__('__builtin__' if PY2 else 'builtins')) 28 builtin_vars = dir(__import__('__builtin__' if PY2 else 'builtins'))
30 29
31 try:
32 import ast
33 except ImportError: # Python 2.5
34 import _ast as ast
35
36 if 'decorator_list' not in ast.ClassDef._fields:
37 # Patch the missing attribute 'decorator_list'
38 ast.ClassDef.decorator_list = ()
39 ast.FunctionDef.decorator_list = property(lambda s: s.decorators)
40
41 from . import messages 30 from . import messages
42 31
43 32
44 if PY2: 33 if PY2:
45 def getNodeType(node_class): 34 def getNodeType(node_class):
46 # workaround str.upper() which is locale-dependent 35 # workaround str.upper() which is locale-dependent
47 return str(unicode(node_class.__name__).upper()) # __IGNORE_WARNING__ 36 return str(unicode(node_class.__name__).upper()) # __IGNORE_WARNING__
37
38 def get_raise_argument(node):
39 return node.type
40
48 else: 41 else:
49 def getNodeType(node_class): 42 def getNodeType(node_class):
50 return node_class.__name__.upper() 43 return node_class.__name__.upper()
51 44
45 def get_raise_argument(node):
46 return node.exc
47
48 # Silence `pyflakes` from reporting `undefined name 'unicode'` in Python 3.
49 unicode = str
50
52 # Python >= 3.3 uses ast.Try instead of (ast.TryExcept + ast.TryFinally) 51 # Python >= 3.3 uses ast.Try instead of (ast.TryExcept + ast.TryFinally)
53 if PY32: 52 if PY2:
54 def getAlternatives(n): 53 def getAlternatives(n):
55 if isinstance(n, (ast.If, ast.TryFinally)): 54 if isinstance(n, (ast.If, ast.TryFinally)):
56 return [n.body] 55 return [n.body]
57 if isinstance(n, ast.TryExcept): 56 if isinstance(n, ast.TryExcept):
58 return [n.body + n.orelse] + [[hdl] for hdl in n.handlers] 57 return [n.body + n.orelse] + [[hdl] for hdl in n.handlers]
133 } 132 }
134 return constants_lookup.get( 133 return constants_lookup.get(
135 result.name, 134 result.name,
136 result, 135 result,
137 ) 136 )
138 elif (not PY33) and isinstance(item, ast.NameConstant): 137 elif (not PY2) and isinstance(item, ast.NameConstant):
139 # None, True, False are nameconstants in python3, but names in 2 138 # None, True, False are nameconstants in python3, but names in 2
140 return item.value 139 return item.value
141 else: 140 else:
142 return UnhandledKeyType() 141 return UnhandledKeyType()
142
143
144 def is_notimplemented_name_node(node):
145 return isinstance(node, ast.Name) and getNodeName(node) == 'NotImplemented'
143 146
144 147
145 class Binding(object): 148 class Binding(object):
146 """ 149 """
147 Represents the binding of a value to a name. 150 Represents the binding of a value to a name.
412 I represent a name scope for a function. 415 I represent a name scope for a function.
413 416
414 @ivar globals: Names declared 'global' in this function. 417 @ivar globals: Names declared 'global' in this function.
415 """ 418 """
416 usesLocals = False 419 usesLocals = False
417 alwaysUsed = set(['__tracebackhide__', 420 alwaysUsed = {'__tracebackhide__', '__traceback_info__',
418 '__traceback_info__', '__traceback_supplement__']) 421 '__traceback_supplement__'}
419 422
420 def __init__(self): 423 def __init__(self):
421 super(FunctionScope, self).__init__() 424 super(FunctionScope, self).__init__()
422 # Simplify: manage the special locals as globals 425 # Simplify: manage the special locals as globals
423 self.globals = self.alwaysUsed.copy() 426 self.globals = self.alwaysUsed.copy()
681 not isinstance(self.getParent(existing.source), 684 not isinstance(self.getParent(existing.source),
682 (ast.For, ast.comprehension))): 685 (ast.For, ast.comprehension))):
683 self.report(messages.RedefinedInListComp, 686 self.report(messages.RedefinedInListComp,
684 node, value.name, existing.source) 687 node, value.name, existing.source)
685 elif not existing.used and value.redefines(existing): 688 elif not existing.used and value.redefines(existing):
686 self.report(messages.RedefinedWhileUnused, 689 if value.name != '_' or isinstance(existing, Importation):
687 node, value.name, existing.source) 690 self.report(messages.RedefinedWhileUnused,
691 node, value.name, existing.source)
688 692
689 elif isinstance(existing, Importation) and value.redefines(existing): 693 elif isinstance(existing, Importation) and value.redefines(existing):
690 existing.redefined.append(node) 694 existing.redefined.append(node)
691 695
692 if value.name in self.scope: 696 if value.name in self.scope:
711 in_generators = None 715 in_generators = None
712 importStarred = None 716 importStarred = None
713 717
714 # try enclosing function scopes and global scope 718 # try enclosing function scopes and global scope
715 for scope in self.scopeStack[-1::-1]: 719 for scope in self.scopeStack[-1::-1]:
716 # only generators used in a class scope can access the names 720 if isinstance(scope, ClassScope):
717 # of the class. this is skipped during the first iteration 721 if not PY2 and name == '__class__':
718 if in_generators is False and isinstance(scope, ClassScope): 722 return
719 continue 723 elif in_generators is False:
724 # only generators used in a class scope can access the
725 # names of the class. this is skipped during the first
726 # iteration
727 continue
720 728
721 try: 729 try:
722 scope[name].used = (self.scope, node) 730 scope[name].used = (self.scope, node)
723 except KeyError: 731 except KeyError:
724 pass 732 pass
875 883
876 _getDoctestExamples = doctest.DocTestParser().get_examples 884 _getDoctestExamples = doctest.DocTestParser().get_examples
877 885
878 def handleDoctests(self, node): 886 def handleDoctests(self, node):
879 try: 887 try:
880 (docstring, node_lineno) = self.getDocstring(node.body[0]) 888 if hasattr(node, 'docstring'):
889 docstring = node.docstring
890
891 # This is just a reasonable guess. In Python 3.7, docstrings no
892 # longer have line numbers associated with them. This will be
893 # incorrect if there are empty lines between the beginning
894 # of the function and the docstring.
895 node_lineno = node.lineno
896 if hasattr(node, 'args'):
897 node_lineno = max([node_lineno] +
898 [arg.lineno for arg in node.args.args])
899 else:
900 (docstring, node_lineno) = self.getDocstring(node.body[0])
881 examples = docstring and self._getDoctestExamples(docstring) 901 examples = docstring and self._getDoctestExamples(docstring)
882 except (ValueError, IndexError): 902 except (ValueError, IndexError):
883 # e.g. line 6 of the docstring for <string> has inconsistent 903 # e.g. line 6 of the docstring for <string> has inconsistent
884 # leading whitespace: ... 904 # leading whitespace: ...
885 return 905 return
912 if not underscore_in_builtins: 932 if not underscore_in_builtins:
913 self.builtIns.remove('_') 933 self.builtIns.remove('_')
914 self.popScope() 934 self.popScope()
915 self.scopeStack = saved_stack 935 self.scopeStack = saved_stack
916 936
937 def handleAnnotation(self, annotation, node):
938 if isinstance(annotation, ast.Str):
939 # Defer handling forward annotation.
940 def handleForwardAnnotation():
941 try:
942 tree = ast.parse(annotation.s)
943 except SyntaxError:
944 self.report(
945 messages.ForwardAnnotationSyntaxError,
946 node,
947 annotation.s,
948 )
949 return
950
951 body = tree.body
952 if len(body) != 1 or not isinstance(body[0], ast.Expr):
953 self.report(
954 messages.ForwardAnnotationSyntaxError,
955 node,
956 annotation.s,
957 )
958 return
959
960 parsed_annotation = tree.body[0].value
961 for descendant in ast.walk(parsed_annotation):
962 ast.copy_location(descendant, annotation)
963
964 self.handleNode(parsed_annotation, node)
965
966 self.deferFunction(handleForwardAnnotation)
967 else:
968 self.handleNode(annotation, node)
969
917 def ignore(self, node): 970 def ignore(self, node):
918 pass 971 pass
919 972
920 # "stmt" type nodes 973 # "stmt" type nodes
921 DELETE = PRINT = FOR = ASYNCFOR = WHILE = IF = WITH = WITHITEM = \ 974 DELETE = PRINT = FOR = ASYNCFOR = WHILE = IF = WITH = WITHITEM = \
922 ASYNCWITH = ASYNCWITHITEM = RAISE = TRYFINALLY = EXEC = \ 975 ASYNCWITH = ASYNCWITHITEM = TRYFINALLY = EXEC = \
923 EXPR = ASSIGN = handleChildren 976 EXPR = ASSIGN = handleChildren
924 977
925 PASS = ignore 978 PASS = ignore
926 979
927 # "expr" type nodes 980 # "expr" type nodes
940 # same for operators 993 # same for operators
941 AND = OR = ADD = SUB = MULT = DIV = MOD = POW = LSHIFT = RSHIFT = \ 994 AND = OR = ADD = SUB = MULT = DIV = MOD = POW = LSHIFT = RSHIFT = \
942 BITOR = BITXOR = BITAND = FLOORDIV = INVERT = NOT = UADD = USUB = \ 995 BITOR = BITXOR = BITAND = FLOORDIV = INVERT = NOT = UADD = USUB = \
943 EQ = NOTEQ = LT = LTE = GT = GTE = IS = ISNOT = IN = NOTIN = \ 996 EQ = NOTEQ = LT = LTE = GT = GTE = IS = ISNOT = IN = NOTIN = \
944 MATMULT = ignore 997 MATMULT = ignore
998
999 def RAISE(self, node):
1000 self.handleChildren(node)
1001
1002 arg = get_raise_argument(node)
1003
1004 if isinstance(arg, ast.Call):
1005 if is_notimplemented_name_node(arg.func):
1006 # Handle "raise NotImplemented(...)"
1007 self.report(messages.RaiseNotImplemented, node)
1008 elif is_notimplemented_name_node(arg):
1009 # Handle "raise NotImplemented"
1010 self.report(messages.RaiseNotImplemented, node)
945 1011
946 # additional node types 1012 # additional node types
947 COMPREHENSION = KEYWORD = FORMATTEDVALUE = JOINEDSTR = handleChildren 1013 COMPREHENSION = KEYWORD = FORMATTEDVALUE = JOINEDSTR = handleChildren
948 1014
949 def DICT(self, node): 1015 def DICT(self, node):
1134 1200
1135 for arg_name in ('vararg', 'kwarg'): 1201 for arg_name in ('vararg', 'kwarg'):
1136 wildcard = getattr(node.args, arg_name) 1202 wildcard = getattr(node.args, arg_name)
1137 if not wildcard: 1203 if not wildcard:
1138 continue 1204 continue
1139 args.append(wildcard if PY33 else wildcard.arg) 1205 args.append(wildcard if PY2 else wildcard.arg)
1140 if is_py3_func: 1206 if is_py3_func:
1141 if PY33: # Python 2.5 to 3.3 1207 if PY2: # Python 2.7
1142 argannotation = arg_name + 'annotation' 1208 argannotation = arg_name + 'annotation'
1143 annotations.append(getattr(node.args, argannotation)) 1209 annotations.append(getattr(node.args, argannotation))
1144 else: # Python >= 3.4 1210 else: # Python >= 3.4
1145 annotations.append(wildcard.annotation) 1211 annotations.append(wildcard.annotation)
1146 1212
1150 if len(set(args)) < len(args): 1216 if len(set(args)) < len(args):
1151 for (idx, arg) in enumerate(args): 1217 for (idx, arg) in enumerate(args):
1152 if arg in args[:idx]: 1218 if arg in args[:idx]:
1153 self.report(messages.DuplicateArgument, node, arg) 1219 self.report(messages.DuplicateArgument, node, arg)
1154 1220
1155 for child in annotations + defaults: 1221 for annotation in annotations:
1156 if child: 1222 self.handleAnnotation(annotation, node)
1157 self.handleNode(child, node) 1223
1224 for default in defaults:
1225 self.handleNode(default, node)
1158 1226
1159 def runFunction(): 1227 def runFunction():
1160 1228
1161 self.pushScope() 1229 self.pushScope()
1162 for name in args: 1230 for name in args:
1175 """ 1243 """
1176 for name, binding in self.scope.unusedAssignments(): 1244 for name, binding in self.scope.unusedAssignments():
1177 self.report(messages.UnusedVariable, binding.source, name) 1245 self.report(messages.UnusedVariable, binding.source, name)
1178 self.deferAssignment(checkUnusedAssignments) 1246 self.deferAssignment(checkUnusedAssignments)
1179 1247
1180 if PY32: 1248 if PY2:
1181 def checkReturnWithArgumentInsideGenerator(): 1249 def checkReturnWithArgumentInsideGenerator():
1182 """ 1250 """
1183 Check to see if there is any return statement with 1251 Check to see if there is any return statement with
1184 arguments but the function is a generator. 1252 arguments but the function is a generator.
1185 """ 1253 """
1312 def EXCEPTHANDLER(self, node): 1380 def EXCEPTHANDLER(self, node):
1313 if PY2 or node.name is None: 1381 if PY2 or node.name is None:
1314 self.handleChildren(node) 1382 self.handleChildren(node)
1315 return 1383 return
1316 1384
1317 # 3.x: the name of the exception, which is not a Name node, but 1385 # If the name already exists in the scope, modify state of existing
1318 # a simple string, creates a local that is only bound within the scope 1386 # binding.
1319 # of the except: block. 1387 if node.name in self.scope:
1388 self.handleNodeStore(node)
1389
1390 # 3.x: the name of the exception, which is not a Name node, but a
1391 # simple string, creates a local that is only bound within the scope of
1392 # the except: block. As such, temporarily remove the existing binding
1393 # to more accurately determine if the name is used in the except:
1394 # block.
1320 1395
1321 for scope in self.scopeStack[::-1]: 1396 for scope in self.scopeStack[::-1]:
1322 if node.name in scope: 1397 try:
1323 is_name_previously_defined = True 1398 binding = scope.pop(node.name)
1399 except KeyError:
1400 pass
1401 else:
1402 prev_definition = scope, binding
1324 break 1403 break
1325 else: 1404 else:
1326 is_name_previously_defined = False 1405 prev_definition = None
1327 1406
1328 self.handleNodeStore(node) 1407 self.handleNodeStore(node)
1329 self.handleChildren(node) 1408 self.handleChildren(node)
1330 if not is_name_previously_defined: 1409
1331 # See discussion on https://github.com/PyCQA/pyflakes/pull/59 1410 # See discussion on https://github.com/PyCQA/pyflakes/pull/59
1332 1411
1333 # We're removing the local name since it's being unbound 1412 # We're removing the local name since it's being unbound after leaving
1334 # after leaving the except: block and it's always unbound 1413 # the except: block and it's always unbound if the except: block is
1335 # if the except: block is never entered. This will cause an 1414 # never entered. This will cause an "undefined name" error raised if
1336 # "undefined name" error raised if the checked code tries to 1415 # the checked code tries to use the name afterwards.
1337 # use the name afterwards. 1416 #
1338 # 1417 # Unless it's been removed already. Then do nothing.
1339 # Unless it's been removed already. Then do nothing. 1418
1340 1419 try:
1341 try: 1420 binding = self.scope.pop(node.name)
1342 del self.scope[node.name] 1421 except KeyError:
1343 except KeyError: 1422 pass
1344 pass 1423 else:
1424 if not binding.used:
1425 self.report(messages.UnusedVariable, node, node.name)
1426
1427 # Restore.
1428 if prev_definition:
1429 scope, binding = prev_definition
1430 scope[node.name] = binding
1345 1431
1346 def ANNASSIGN(self, node): 1432 def ANNASSIGN(self, node):
1347 """
1348 Annotated assignments don't have annotations evaluated on function
1349 scope, hence the custom implementation.
1350
1351 See: PEP 526.
1352 """
1353 if node.value: 1433 if node.value:
1354 # Only bind the *targets* if the assignment has a value. 1434 # Only bind the *targets* if the assignment has a value.
1355 # Otherwise it's not really ast.Store and shouldn't silence 1435 # Otherwise it's not really ast.Store and shouldn't silence
1356 # UndefinedLocal warnings. 1436 # UndefinedLocal warnings.
1357 self.handleNode(node.target, node) 1437 self.handleNode(node.target, node)
1358 if not isinstance(self.scope, FunctionScope): 1438 self.handleAnnotation(node.annotation, node)
1359 self.handleNode(node.annotation, node)
1360 if node.value: 1439 if node.value:
1361 # If the assignment has value, handle the *value* now. 1440 # If the assignment has value, handle the *value* now.
1362 self.handleNode(node.value, node) 1441 self.handleNode(node.value, node)
1363 1442
1364 1443

eric ide

mercurial