Statistics
| Revision:

gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / pylint / checkers / typecheck.py @ 745

History | View | Annotate | Download (39.8 KB)

1
# Copyright (c) 2006-2013 LOGILAB S.A. (Paris, FRANCE).
2
# http://www.logilab.fr/ -- mailto:contact@logilab.fr
3
#
4
# This program is free software; you can redistribute it and/or modify it under
5
# the terms of the GNU General Public License as published by the Free Software
6
# Foundation; either version 2 of the License, or (at your option) any later
7
# version.
8
#
9
# This program is distributed in the hope that it will be useful, but WITHOUT
10
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License along with
14
# this program; if not, write to the Free Software Foundation, Inc.,
15
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16
"""try to find more bugs in the code using astroid inference capabilities
17
"""
18

    
19
import collections
20
import fnmatch
21
import re
22
import shlex
23
import sys
24

    
25
import six
26

    
27
import astroid
28
import astroid.context
29
import astroid.arguments
30
from astroid import exceptions
31
from astroid import objects
32
from astroid import bases
33

    
34
from pylint.interfaces import IAstroidChecker, INFERENCE, INFERENCE_FAILURE
35
from pylint.checkers import BaseChecker
36
from pylint.checkers.utils import (
37
    is_super, check_messages, decorated_with_property,
38
    decorated_with, node_ignores_exception,
39
    is_iterable, is_mapping, supports_membership_test,
40
    is_comprehension, is_inside_abstract_class,
41
    supports_subscript,
42
    safe_infer,
43
    has_known_bases)
44
from pylint import utils
45

    
46

    
47
_ZOPE_DEPRECATED = (
48
    "This option is deprecated. Use generated-members instead."
49
)
50
BUILTINS = six.moves.builtins.__name__
51
STR_FORMAT = "%s.str.format" % BUILTINS
52

    
53

    
54
def _unflatten(iterable):
55
    for index, elem in enumerate(iterable):
56
        if (isinstance(elem, collections.Sequence) and
57
                not isinstance(elem, six.string_types)):
58
            for elem in _unflatten(elem):
59
                yield elem
60
        elif elem and not index:
61
            # We're interested only in the first element.
62
            yield elem
63

    
64

    
65
def _is_owner_ignored(owner, name, ignored_classes, ignored_modules):
66
    """Check if the given owner should be ignored
67

68
    This will verify if the owner's module is in *ignored_modules*
69
    or the owner's module fully qualified name is in *ignored_modules*
70
    or if the *ignored_modules* contains a pattern which catches
71
    the fully qualified name of the module.
72

73
    Also, similar checks are done for the owner itself, if its name
74
    matches any name from the *ignored_classes* or if its qualified
75
    name can be found in *ignored_classes*.
76
    """
77
    ignored_modules = set(ignored_modules)
78
    module_name = owner.root().name
79
    module_qname = owner.root().qname()
80
    if any(module_name in ignored_modules or
81
           module_qname in ignored_modules or
82
           fnmatch.fnmatch(module_qname, ignore) for ignore in ignored_modules):
83
        return True
84

    
85
    ignored_classes = set(ignored_classes)
86
    if hasattr(owner, 'qname'):
87
        qname = owner.qname()
88
    else:
89
        qname = ''
90
    return any(name == ignore or qname == ignore for ignore in ignored_classes)
91

    
92

    
93
MSGS = {
94
    'E1101': ('%s %r has no %r member',
95
              'no-member',
96
              'Used when a variable is accessed for an unexistent member.',
97
              {'old_names': [('E1103', 'maybe-no-member')]}),
98
    'E1102': ('%s is not callable',
99
              'not-callable',
100
              'Used when an object being called has been inferred to a non \
101
              callable object'),
102
    'E1111': ('Assigning to function call which doesn\'t return',
103
              'assignment-from-no-return',
104
              'Used when an assignment is done on a function call but the \
105
              inferred function doesn\'t return anything.'),
106
    'E1120': ('No value for argument %s in %s call',
107
              'no-value-for-parameter',
108
              'Used when a function call passes too few arguments.'),
109
    'E1121': ('Too many positional arguments for %s call',
110
              'too-many-function-args',
111
              'Used when a function call passes too many positional \
112
              arguments.'),
113
    'E1123': ('Unexpected keyword argument %r in %s call',
114
              'unexpected-keyword-arg',
115
              'Used when a function call passes a keyword argument that \
116
              doesn\'t correspond to one of the function\'s parameter names.'),
117
    'E1124': ('Argument %r passed by position and keyword in %s call',
118
              'redundant-keyword-arg',
119
              'Used when a function call would result in assigning multiple \
120
              values to a function parameter, one value from a positional \
121
              argument and one from a keyword argument.'),
122
    'E1125': ('Missing mandatory keyword argument %r in %s call',
123
              'missing-kwoa',
124
              ('Used when a function call does not pass a mandatory'
125
               ' keyword-only argument.'),
126
              {'minversion': (3, 0)}),
127
    'E1126': ('Sequence index is not an int, slice, or instance with __index__',
128
              'invalid-sequence-index',
129
              'Used when a sequence type is indexed with an invalid type. '
130
              'Valid types are ints, slices, and objects with an __index__ '
131
              'method.'),
132
    'E1127': ('Slice index is not an int, None, or instance with __index__',
133
              'invalid-slice-index',
134
              'Used when a slice index is not an integer, None, or an object \
135
               with an __index__ method.'),
136
    'E1128': ('Assigning to function call which only returns None',
137
              'assignment-from-none',
138
              'Used when an assignment is done on a function call but the '
139
              'inferred function returns nothing but None.',
140
              {'old_names': [('W1111', 'assignment-from-none')]}),
141
    'E1129': ("Context manager '%s' doesn't implement __enter__ and __exit__.",
142
              'not-context-manager',
143
              'Used when an instance in a with statement doesn\'t implement '
144
              'the context manager protocol(__enter__/__exit__).'),
145
    'E1130': ('%s',
146
              'invalid-unary-operand-type',
147
              'Emitted when an unary operand is used on an object which does not '
148
              'support this type of operation'),
149
    'E1131': ('%s',
150
              'unsupported-binary-operation',
151
              'Emitted when a binary arithmetic operation between two '
152
              'operands is not supported.'),
153
    'E1132': ('Got multiple values for keyword argument %r in function call',
154
              'repeated-keyword',
155
              'Emitted when a function call got multiple values for a keyword.'),
156
    'E1135': ("Value '%s' doesn't support membership test",
157
              'unsupported-membership-test',
158
              'Emitted when an instance in membership test expression doesn\'t'
159
              'implement membership protocol (__contains__/__iter__/__getitem__)'),
160
    'E1136': ("Value '%s' is unsubscriptable",
161
              'unsubscriptable-object',
162
              "Emitted when a subscripted value doesn't support subscription"
163
              "(i.e. doesn't define __getitem__ method)"),
164
    }
165

    
166
# builtin sequence types in Python 2 and 3.
167
SEQUENCE_TYPES = set(['str', 'unicode', 'list', 'tuple', 'bytearray',
168
                      'xrange', 'range', 'bytes', 'memoryview'])
169

    
170

    
171
def _emit_no_member(node, owner, owner_name, ignored_mixins):
172
    """Try to see if no-member should be emitted for the given owner.
173

174
    The following cases are ignored:
175

176
        * the owner is a function and it has decorators.
177
        * the owner is an instance and it has __getattr__, __getattribute__ implemented
178
        * the module is explicitly ignored from no-member checks
179
        * the owner is a class and the name can be found in its metaclass.
180
        * The access node is protected by an except handler, which handles
181
          AttributeError, Exception or bare except.
182
    """
183
    if node_ignores_exception(node, AttributeError):
184
        return False
185
    # skip None anyway
186
    if isinstance(owner, astroid.Const) and owner.value is None:
187
        return False
188
    if is_super(owner) or getattr(owner, 'type', None) == 'metaclass':
189
        return False
190
    if ignored_mixins and owner_name[-5:].lower() == 'mixin':
191
        return False
192
    if isinstance(owner, astroid.FunctionDef) and owner.decorators:
193
        return False
194
    if isinstance(owner, astroid.Instance):
195
        if owner.has_dynamic_getattr() or not has_known_bases(owner):
196
            return False
197
    if isinstance(owner, objects.Super):
198
        # Verify if we are dealing with an invalid Super object.
199
        # If it is invalid, then there's no point in checking that
200
        # it has the required attribute. Also, don't fail if the
201
        # MRO is invalid.
202
        try:
203
            owner.super_mro()
204
        except (exceptions.MroError, exceptions.SuperError):
205
            return False
206
        if not all(map(has_known_bases, owner.type.mro())):
207
            return False
208
    return True
209

    
210

    
211
def _determine_callable(callable_obj):
212
    # Ordering is important, since BoundMethod is a subclass of UnboundMethod,
213
    # and Function inherits Lambda.
214
    if isinstance(callable_obj, astroid.BoundMethod):
215
        # Bound methods have an extra implicit 'self' argument.
216
        return callable_obj, 1, callable_obj.type
217
    elif isinstance(callable_obj, astroid.UnboundMethod):
218
        return callable_obj, 0, 'unbound method'
219
    elif isinstance(callable_obj, astroid.FunctionDef):
220
        return callable_obj, 0, callable_obj.type
221
    elif isinstance(callable_obj, astroid.Lambda):
222
        return callable_obj, 0, 'lambda'
223
    elif isinstance(callable_obj, astroid.ClassDef):
224
        # Class instantiation, lookup __new__ instead.
225
        # If we only find object.__new__, we can safely check __init__
226
        # instead. If __new__ belongs to builtins, then we look
227
        # again for __init__ in the locals, since we won't have
228
        # argument information for the builtin __new__ function.
229
        try:
230
            # Use the last definition of __new__.
231
            new = callable_obj.local_attr('__new__')[-1]
232
        except exceptions.NotFoundError:
233
            new = None
234

    
235
        from_object = new and new.parent.scope().name == 'object'
236
        from_builtins = new and new.root().name in sys.builtin_module_names
237

    
238
        if not new or from_object or from_builtins:
239
            try:
240
                # Use the last definition of __init__.
241
                callable_obj = callable_obj.local_attr('__init__')[-1]
242
            except exceptions.NotFoundError:
243
                # do nothing, covered by no-init.
244
                raise ValueError
245
        else:
246
            callable_obj = new
247

    
248
        if not isinstance(callable_obj, astroid.FunctionDef):
249
            raise ValueError
250
        # both have an extra implicit 'cls'/'self' argument.
251
        return callable_obj, 1, 'constructor'
252
    else:
253
        raise ValueError
254

    
255
class TypeChecker(BaseChecker):
256
    """try to find bugs in the code using type inference
257
    """
258

    
259
    __implements__ = (IAstroidChecker,)
260

    
261
    # configuration section name
262
    name = 'typecheck'
263
    # messages
264
    msgs = MSGS
265
    priority = -1
266
    # configuration options
267
    options = (('ignore-mixin-members',
268
                {'default' : True, 'type' : 'yn', 'metavar': '<y_or_n>',
269
                 'help' : 'Tells whether missing members accessed in mixin \
270
class should be ignored. A mixin class is detected if its name ends with \
271
"mixin" (case insensitive).'}
272
               ),
273
               ('ignored-modules',
274
                {'default': (),
275
                 'type': 'csv',
276
                 'metavar': '<module names>',
277
                 'help': 'List of module names for which member attributes '
278
                         'should not be checked (useful for modules/projects '
279
                         'where namespaces are manipulated during runtime and '
280
                         'thus existing member attributes cannot be '
281
                         'deduced by static analysis. It supports qualified '
282
                         'module names, as well as Unix pattern matching.'}
283
               ),
284
               ('ignored-classes',
285
                {'default' : (),
286
                 'type' : 'csv',
287
                 'metavar' : '<members names>',
288
                 'help' : 'List of classes names for which member attributes '
289
                          'should not be checked (useful for classes with '
290
                          'attributes dynamically set). This supports '
291
                          'can work with qualified names.'}
292
               ),
293

    
294
               ('zope', utils.deprecated_option(opt_type='yn',
295
                                                help_msg=_ZOPE_DEPRECATED)),
296

    
297
               ('generated-members',
298
                {'default' : (),
299
                 'type' : 'string',
300
                 'metavar' : '<members names>',
301
                 'help' : 'List of members which are set dynamically and \
302
missed by pylint inference system, and so shouldn\'t trigger E1101 when \
303
accessed. Python regular expressions are accepted.'}
304
               ),
305
              )
306

    
307
    def open(self):
308
        # do this in open since config not fully initialized in __init__
309
        # generated_members may contain regular expressions
310
        # (surrounded by quote `"` and followed by a comma `,`)
311
        # REQUEST,aq_parent,"[a-zA-Z]+_set{1,2}"' =>
312
        # ('REQUEST', 'aq_parent', '[a-zA-Z]+_set{1,2}')
313
        if isinstance(self.config.generated_members, str):
314
            gen = shlex.shlex(self.config.generated_members)
315
            gen.whitespace += ','
316
            gen.wordchars += '[]-+'
317
            self.config.generated_members = tuple(tok.strip('"') for tok in gen)
318

    
319
    def visit_assignattr(self, node):
320
        if isinstance(node.assign_type(), astroid.AugAssign):
321
            self.visit_attribute(node)
322

    
323
    def visit_delattr(self, node):
324
        self.visit_attribute(node)
325

    
326
    @check_messages('no-member')
327
    def visit_attribute(self, node):
328
        """check that the accessed attribute exists
329

330
        to avoid too much false positives for now, we'll consider the code as
331
        correct if a single of the inferred nodes has the accessed attribute.
332

333
        function/method, super call and metaclasses are ignored
334
        """
335
        for pattern in self.config.generated_members:
336
            # attribute is marked as generated, stop here
337
            if re.match(pattern, node.attrname):
338
                return
339

    
340
        try:
341
            infered = list(node.expr.infer())
342
        except exceptions.InferenceError:
343
            return
344
        # list of (node, nodename) which are missing the attribute
345
        missingattr = set()
346
        inference_failure = False
347
        for owner in infered:
348
            # skip yes object
349
            if owner is astroid.YES:
350
                inference_failure = True
351
                continue
352

    
353
            name = getattr(owner, 'name', None)
354
            if _is_owner_ignored(owner, name, self.config.ignored_classes,
355
                                 self.config.ignored_modules):
356
                continue
357

    
358
            try:
359
                if not [n for n in owner.getattr(node.attrname)
360
                        if not isinstance(n.statement(), astroid.AugAssign)]:
361
                    missingattr.add((owner, name))
362
                    continue
363
            except AttributeError:
364
                # XXX method / function
365
                continue
366
            except exceptions.NotFoundError:
367
                # This can't be moved before the actual .getattr call,
368
                # because there can be more values inferred and we are
369
                # stopping after the first one which has the attribute in question.
370
                # The problem is that if the first one has the attribute,
371
                # but we continue to the next values which doesn't have the
372
                # attribute, then we'll have a false positive.
373
                # So call this only after the call has been made.
374
                if not _emit_no_member(node, owner, name,
375
                                       self.config.ignore_mixin_members):
376
                    continue
377
                missingattr.add((owner, name))
378
                continue
379
            # stop on the first found
380
            break
381
        else:
382
            # we have not found any node with the attributes, display the
383
            # message for infered nodes
384
            done = set()
385
            for owner, name in missingattr:
386
                if isinstance(owner, astroid.Instance):
387
                    actual = owner._proxied
388
                else:
389
                    actual = owner
390
                if actual in done:
391
                    continue
392
                done.add(actual)
393
                confidence = INFERENCE if not inference_failure else INFERENCE_FAILURE
394
                self.add_message('no-member', node=node,
395
                                 args=(owner.display_type(), name,
396
                                       node.attrname),
397
                                 confidence=confidence)
398

    
399
    @check_messages('assignment-from-no-return', 'assignment-from-none')
400
    def visit_assign(self, node):
401
        """check that if assigning to a function call, the function is
402
        possibly returning something valuable
403
        """
404
        if not isinstance(node.value, astroid.Call):
405
            return
406
        function_node = safe_infer(node.value.func)
407
        # skip class, generator and incomplete function definition
408
        if not (isinstance(function_node, astroid.FunctionDef) and
409
                function_node.root().fully_defined()):
410
            return
411
        if function_node.is_generator() \
412
               or function_node.is_abstract(pass_is_abstract=False):
413
            return
414
        returns = list(function_node.nodes_of_class(astroid.Return,
415
                                                    skip_klass=astroid.FunctionDef))
416
        if len(returns) == 0:
417
            self.add_message('assignment-from-no-return', node=node)
418
        else:
419
            for rnode in returns:
420
                if not (isinstance(rnode.value, astroid.Const)
421
                        and rnode.value.value is None
422
                        or rnode.value is None):
423
                    break
424
            else:
425
                self.add_message('assignment-from-none', node=node)
426

    
427
    def _check_uninferable_callfunc(self, node):
428
        """
429
        Check that the given uninferable CallFunc node does not
430
        call an actual function.
431
        """
432
        if not isinstance(node.func, astroid.Attribute):
433
            return
434

    
435
        # Look for properties. First, obtain
436
        # the lhs of the Getattr node and search the attribute
437
        # there. If that attribute is a property or a subclass of properties,
438
        # then most likely it's not callable.
439

    
440
        # TODO: since astroid doesn't understand descriptors very well
441
        # we will not handle them here, right now.
442

    
443
        expr = node.func.expr
444
        klass = safe_infer(expr)
445
        if (klass is None or klass is astroid.YES or
446
                not isinstance(klass, astroid.Instance)):
447
            return
448

    
449
        try:
450
            attrs = klass._proxied.getattr(node.func.attrname)
451
        except exceptions.NotFoundError:
452
            return
453

    
454
        for attr in attrs:
455
            if attr is astroid.YES:
456
                continue
457
            if not isinstance(attr, astroid.FunctionDef):
458
                continue
459

    
460
            # Decorated, see if it is decorated with a property.
461
            # Also, check the returns and see if they are callable.
462
            if decorated_with_property(attr):
463
                if all(return_node.callable()
464
                       for return_node in attr.infer_call_result(node)):
465
                    continue
466
                else:
467
                    self.add_message('not-callable', node=node,
468
                                     args=node.func.as_string())
469
                    break
470

    
471
    @staticmethod
472
    def _no_context_variadic(node):
473
        """Verify if the given call node has variadic nodes without context
474

475
        This is a workaround for handling cases of nested call functions
476
        which don't have the specific call context at hand.
477
        Variadic arguments (variable positional arguments and variable
478
        keyword arguments) are inferred, inherently wrong, by astroid
479
        as a Tuple, respectively a Dict with empty elements.
480
        This can lead pylint to believe that a function call receives
481
        too few arguments.
482
        """
483
        for arg in node.args:
484
            if not isinstance(arg, astroid.Starred):
485
                continue
486

    
487
            inferred = safe_infer(arg.value)
488
            if isinstance(inferred, astroid.Tuple):
489
                length = len(inferred.elts)
490
            elif isinstance(inferred, astroid.Dict):
491
                length = len(inferred.items)
492
            else:
493
                return False
494
            if not length and isinstance(inferred.statement(), astroid.FunctionDef):
495
                return True
496
        return False
497

    
498
    @check_messages(*(list(MSGS.keys())))
499
    def visit_call(self, node):
500
        """check that called functions/methods are inferred to callable objects,
501
        and that the arguments passed to the function match the parameters in
502
        the inferred function's definition
503
        """
504
        # Build the set of keyword arguments, checking for duplicate keywords,
505
        # and count the positional arguments.
506
        call_site = astroid.arguments.CallSite.from_call(node)
507
        num_positional_args = len(call_site.positional_arguments)
508
        keyword_args = list(call_site.keyword_arguments.keys())
509
        no_context_variadic = self._no_context_variadic(node)
510

    
511
        called = safe_infer(node.func)
512
        # only function, generator and object defining __call__ are allowed
513
        if called is not None and not called.callable():
514
            self.add_message('not-callable', node=node,
515
                             args=node.func.as_string())
516

    
517
        self._check_uninferable_callfunc(node)
518

    
519
        try:
520
            called, implicit_args, callable_name = _determine_callable(called)
521
        except ValueError:
522
            # Any error occurred during determining the function type, most of
523
            # those errors are handled by different warnings.
524
            return
525

    
526
        num_positional_args += implicit_args
527
        if called.args.args is None:
528
            # Built-in functions have no argument information.
529
            return
530

    
531
        if len(called.argnames()) != len(set(called.argnames())):
532
            # Duplicate parameter name (see duplicate-argument).  We can't really
533
            # make sense of the function call in this case, so just return.
534
            return
535

    
536
        # Warn about duplicated keyword arguments, such as `f=24, **{'f': 24}`
537
        for keyword in call_site.duplicated_keywords:
538
            self.add_message('repeated-keyword',
539
                             node=node, args=(keyword, ))
540

    
541
        if call_site.has_invalid_arguments() or call_site.has_invalid_keywords():
542
            # Can't make sense of this.
543
            return
544

    
545
        # Analyze the list of formal parameters.
546
        num_mandatory_parameters = len(called.args.args) - len(called.args.defaults)
547
        parameters = []
548
        parameter_name_to_index = {}
549
        for i, arg in enumerate(called.args.args):
550
            if isinstance(arg, astroid.Tuple):
551
                name = None
552
                # Don't store any parameter names within the tuple, since those
553
                # are not assignable from keyword arguments.
554
            else:
555
                assert isinstance(arg, astroid.AssignName)
556
                # This occurs with:
557
                #    def f( (a), (b) ): pass
558
                name = arg.name
559
                parameter_name_to_index[name] = i
560
            if i >= num_mandatory_parameters:
561
                defval = called.args.defaults[i - num_mandatory_parameters]
562
            else:
563
                defval = None
564
            parameters.append([(name, defval), False])
565

    
566
        kwparams = {}
567
        for i, arg in enumerate(called.args.kwonlyargs):
568
            if isinstance(arg, astroid.Keyword):
569
                name = arg.arg
570
            else:
571
                assert isinstance(arg, astroid.AssignName)
572
                name = arg.name
573
            kwparams[name] = [called.args.kw_defaults[i], False]
574

    
575
        # Match the supplied arguments against the function parameters.
576

    
577
        # 1. Match the positional arguments.
578
        for i in range(num_positional_args):
579
            if i < len(parameters):
580
                parameters[i][1] = True
581
            elif called.args.vararg is not None:
582
                # The remaining positional arguments get assigned to the *args
583
                # parameter.
584
                break
585
            else:
586
                # Too many positional arguments.
587
                self.add_message('too-many-function-args',
588
                                 node=node, args=(callable_name,))
589
                break
590

    
591
        # 2. Match the keyword arguments.
592
        for keyword in keyword_args:
593
            if keyword in parameter_name_to_index:
594
                i = parameter_name_to_index[keyword]
595
                if parameters[i][1]:
596
                    # Duplicate definition of function parameter.
597

    
598
                    # Might be too hardcoded, but this can actually
599
                    # happen when using str.format and `self` is passed
600
                    # by keyword argument, as in `.format(self=self)`.
601
                    # It's perfectly valid to so, so we're just skipping
602
                    # it if that's the case.
603
                    if not (keyword == 'self' and called.qname() == STR_FORMAT):
604
                        self.add_message('redundant-keyword-arg',
605
                                         node=node, args=(keyword, callable_name))
606
                else:
607
                    parameters[i][1] = True
608
            elif keyword in kwparams:
609
                if kwparams[keyword][1]:  # XXX is that even possible?
610
                    # Duplicate definition of function parameter.
611
                    self.add_message('redundant-keyword-arg', node=node,
612
                                     args=(keyword, callable_name))
613
                else:
614
                    kwparams[keyword][1] = True
615
            elif called.args.kwarg is not None:
616
                # The keyword argument gets assigned to the **kwargs parameter.
617
                pass
618
            else:
619
                # Unexpected keyword argument.
620
                self.add_message('unexpected-keyword-arg', node=node,
621
                                 args=(keyword, callable_name))
622

    
623
        # 3. Match the **kwargs, if any.
624
        if node.kwargs:
625
            for i, [(name, defval), assigned] in enumerate(parameters):
626
                # Assume that *kwargs provides values for all remaining
627
                # unassigned named parameters.
628
                if name is not None:
629
                    parameters[i][1] = True
630
                else:
631
                    # **kwargs can't assign to tuples.
632
                    pass
633

    
634
        # Check that any parameters without a default have been assigned
635
        # values.
636
        for [(name, defval), assigned] in parameters:
637
            if (defval is None) and not assigned:
638
                if name is None:
639
                    display_name = '<tuple>'
640
                else:
641
                    display_name = repr(name)
642
                # TODO(cpopa): this should be removed after PyCQA/astroid/issues/177
643
                if not no_context_variadic:
644
                    self.add_message('no-value-for-parameter', node=node,
645
                                     args=(display_name, callable_name))
646

    
647
        for name in kwparams:
648
            defval, assigned = kwparams[name]
649
            if defval is None and not assigned:
650
                self.add_message('missing-kwoa', node=node,
651
                                 args=(name, callable_name))
652

    
653
    @check_messages('invalid-sequence-index')
654
    def visit_extslice(self, node):
655
        # Check extended slice objects as if they were used as a sequence
656
        # index to check if the object being sliced can support them
657
        return self.visit_index(node)
658

    
659
    @check_messages('invalid-sequence-index')
660
    def visit_index(self, node):
661
        if not node.parent or not hasattr(node.parent, "value"):
662
            return
663
        # Look for index operations where the parent is a sequence type.
664
        # If the types can be determined, only allow indices to be int,
665
        # slice or instances with __index__.
666
        parent_type = safe_infer(node.parent.value)
667
        if not isinstance(parent_type, (astroid.ClassDef, astroid.Instance)):
668
            return
669

    
670
        # Determine what method on the parent this index will use
671
        # The parent of this node will be a Subscript, and the parent of that
672
        # node determines if the Subscript is a get, set, or delete operation.
673
        operation = node.parent.parent
674
        if isinstance(operation, astroid.Assign):
675
            methodname = '__setitem__'
676
        elif isinstance(operation, astroid.Delete):
677
            methodname = '__delitem__'
678
        else:
679
            methodname = '__getitem__'
680

    
681
        # Check if this instance's __getitem__, __setitem__, or __delitem__, as
682
        # appropriate to the statement, is implemented in a builtin sequence
683
        # type. This way we catch subclasses of sequence types but skip classes
684
        # that override __getitem__ and which may allow non-integer indices.
685
        try:
686
            methods = parent_type.getattr(methodname)
687
            if methods is astroid.YES:
688
                return
689
            itemmethod = methods[0]
690
        except (exceptions.NotFoundError, IndexError):
691
            return
692
        if not isinstance(itemmethod, astroid.FunctionDef):
693
            return
694
        if itemmethod.root().name != BUILTINS:
695
            return
696
        if not itemmethod.parent:
697
            return
698
        if itemmethod.parent.name not in SEQUENCE_TYPES:
699
            return
700

    
701
        # For ExtSlice objects coming from visit_extslice, no further
702
        # inference is necessary, since if we got this far the ExtSlice
703
        # is an error.
704
        if isinstance(node, astroid.ExtSlice):
705
            index_type = node
706
        else:
707
            index_type = safe_infer(node)
708
        if index_type is None or index_type is astroid.YES:
709
            return
710
        # Constants must be of type int
711
        if isinstance(index_type, astroid.Const):
712
            if isinstance(index_type.value, int):
713
                return
714
        # Instance values must be int, slice, or have an __index__ method
715
        elif isinstance(index_type, astroid.Instance):
716
            if index_type.pytype() in (BUILTINS + '.int', BUILTINS + '.slice'):
717
                return
718
            try:
719
                index_type.getattr('__index__')
720
                return
721
            except exceptions.NotFoundError:
722
                pass
723
        elif isinstance(index_type, astroid.Slice):
724
            # Delegate to visit_slice. A slice can be present
725
            # here after inferring the index node, which could
726
            # be a `slice(...)` call for instance.
727
            return self.visit_slice(index_type)
728

    
729
        # Anything else is an error
730
        self.add_message('invalid-sequence-index', node=node)
731

    
732
    @check_messages('invalid-slice-index')
733
    def visit_slice(self, node):
734
        # Check the type of each part of the slice
735
        for index in (node.lower, node.upper, node.step):
736
            if index is None:
737
                continue
738

    
739
            index_type = safe_infer(index)
740
            if index_type is None or index_type is astroid.YES:
741
                continue
742

    
743
            # Constants must of type int or None
744
            if isinstance(index_type, astroid.Const):
745
                if isinstance(index_type.value, (int, type(None))):
746
                    continue
747
            # Instance values must be of type int, None or an object
748
            # with __index__
749
            elif isinstance(index_type, astroid.Instance):
750
                if index_type.pytype() in (BUILTINS + '.int',
751
                                           BUILTINS + '.NoneType'):
752
                    continue
753

    
754
                try:
755
                    index_type.getattr('__index__')
756
                    return
757
                except exceptions.NotFoundError:
758
                    pass
759

    
760
            # Anything else is an error
761
            self.add_message('invalid-slice-index', node=node)
762

    
763
    @check_messages('not-context-manager')
764
    def visit_with(self, node):
765
        for ctx_mgr, _ in node.items:
766
            context = astroid.context.InferenceContext()
767
            infered = safe_infer(ctx_mgr, context=context)
768
            if infered is None or infered is astroid.YES:
769
                continue
770

    
771
            if isinstance(infered, bases.Generator):
772
                # Check if we are dealing with a function decorated
773
                # with contextlib.contextmanager.
774
                if decorated_with(infered.parent, ['contextlib.contextmanager']):
775
                    continue
776
                # If the parent of the generator is not the context manager itself,
777
                # that means that it could have been returned from another
778
                # function which was the real context manager.
779
                # The following approach is more of a hack rather than a real
780
                # solution: walk all the inferred statements for the
781
                # given *ctx_mgr* and if you find one function scope
782
                # which is decorated, consider it to be the real
783
                # manager and give up, otherwise emit not-context-manager.
784
                # See the test file for not_context_manager for a couple
785
                # of self explaining tests.
786
                for path in six.moves.filter(None, _unflatten(context.path)):
787
                    scope = path.scope()
788
                    if not isinstance(scope, astroid.FunctionDef):
789
                        continue
790
                    if decorated_with(scope, ['contextlib.contextmanager']):
791
                        break
792
                else:
793
                    self.add_message('not-context-manager',
794
                                     node=node, args=(infered.name, ))
795
            else:
796
                try:
797
                    infered.getattr('__enter__')
798
                    infered.getattr('__exit__')
799
                except exceptions.NotFoundError:
800
                    if isinstance(infered, astroid.Instance):
801
                        # If we do not know the bases of this class,
802
                        # just skip it.
803
                        if not has_known_bases(infered):
804
                            continue
805
                        # Just ignore mixin classes.
806
                        if self.config.ignore_mixin_members:
807
                            if infered.name[-5:].lower() == 'mixin':
808
                                continue
809

    
810
                    self.add_message('not-context-manager',
811
                                     node=node, args=(infered.name, ))
812

    
813
    # Disabled until we'll have a more capable astroid.
814
    @check_messages('invalid-unary-operand-type')
815
    def _visit_unaryop(self, node):
816
        """Detect TypeErrors for unary operands."""
817

    
818
        for error in node.type_errors():
819
            # Let the error customize its output.
820
            self.add_message('invalid-unary-operand-type',
821
                             args=str(error), node=node)
822

    
823
    @check_messages('unsupported-binary-operation')
824
    def _visit_binop(self, node):
825
        """Detect TypeErrors for binary arithmetic operands."""
826
        self._check_binop_errors(node)
827

    
828
    @check_messages('unsupported-binary-operation')
829
    def _visit_augassign(self, node):
830
        """Detect TypeErrors for augmented binary arithmetic operands."""
831
        self._check_binop_errors(node)
832

    
833
    def _check_binop_errors(self, node):
834
        for error in node.type_errors():
835
            # Let the error customize its output.
836
            self.add_message('unsupported-binary-operation',
837
                             args=str(error), node=node)
838

    
839
    def _check_membership_test(self, node):
840
        if is_inside_abstract_class(node):
841
            return
842
        if is_comprehension(node):
843
            return
844
        infered = safe_infer(node)
845
        if infered is None or infered is astroid.YES:
846
            return
847
        if not supports_membership_test(infered):
848
            self.add_message('unsupported-membership-test',
849
                             args=node.as_string(),
850
                             node=node)
851

    
852
    @check_messages('unsupported-membership-test')
853
    def visit_compare(self, node):
854
        if len(node.ops) != 1:
855
            return
856
        operator, right = node.ops[0]
857
        if operator in ['in', 'not in']:
858
            self._check_membership_test(right)
859

    
860
    @check_messages('unsubscriptable-object')
861
    def visit_subscript(self, node):
862
        if isinstance(node.value, (astroid.ListComp, astroid.DictComp)):
863
            return
864
        if isinstance(node.value, astroid.SetComp):
865
            self.add_message('unsubscriptable-object',
866
                             args=node.value.as_string(),
867
                             node=node.value)
868
            return
869

    
870
        infered = safe_infer(node.value)
871
        if infered is None or infered is astroid.YES:
872
            return
873

    
874
        if is_inside_abstract_class(node):
875
            return
876

    
877
        if not supports_subscript(infered):
878
            self.add_message('unsubscriptable-object',
879
                             args=node.value.as_string(),
880
                             node=node.value)
881

    
882

    
883

    
884
class IterableChecker(BaseChecker):
885
    """
886
    Checks for non-iterables used in an iterable context.
887
    Contexts include:
888
    - for-statement
889
    - starargs in function call
890
    - `yield from`-statement
891
    - list, dict and set comprehensions
892
    - generator expressions
893
    Also checks for non-mappings in function call kwargs.
894
    """
895

    
896
    __implements__ = (IAstroidChecker,)
897
    name = 'iterable_check'
898

    
899
    msgs = {'E1133': ('Non-iterable value %s is used in an iterating context',
900
                      'not-an-iterable',
901
                      'Used when a non-iterable value is used in place where'
902
                      'iterable is expected'),
903
            'E1134': ('Non-mapping value %s is used in a mapping context',
904
                      'not-a-mapping',
905
                      'Used when a non-mapping value is used in place where'
906
                      'mapping is expected'),
907
           }
908

    
909
    def _check_iterable(self, node):
910
        if is_inside_abstract_class(node):
911
            return
912
        if is_comprehension(node):
913
            return
914
        infered = safe_infer(node)
915
        if infered is None or infered is astroid.YES:
916
            return
917
        if not is_iterable(infered):
918
            self.add_message('not-an-iterable',
919
                             args=node.as_string(),
920
                             node=node)
921

    
922
    def _check_mapping(self, node):
923
        if is_inside_abstract_class(node):
924
            return
925
        if isinstance(node, astroid.DictComp):
926
            return
927
        infered = safe_infer(node)
928
        if infered is None or infered is astroid.YES:
929
            return
930
        if not is_mapping(infered):
931
            self.add_message('not-a-mapping',
932
                             args=node.as_string(),
933
                             node=node)
934

    
935
    @check_messages('not-an-iterable')
936
    def visit_for(self, node):
937
        self._check_iterable(node.iter)
938

    
939
    @check_messages('not-an-iterable')
940
    def visit_yieldfrom(self, node):
941
        self._check_iterable(node.value)
942

    
943
    @check_messages('not-an-iterable', 'not-a-mapping')
944
    def visit_call(self, node):
945
        for stararg in node.starargs:
946
            self._check_iterable(stararg.value)
947
        for kwarg in node.kwargs:
948
            self._check_mapping(kwarg.value)
949

    
950
    @check_messages('not-an-iterable')
951
    def visit_listcomp(self, node):
952
        for gen in node.generators:
953
            self._check_iterable(gen.iter)
954

    
955
    @check_messages('not-an-iterable')
956
    def visit_dictcomp(self, node):
957
        for gen in node.generators:
958
            self._check_iterable(gen.iter)
959

    
960
    @check_messages('not-an-iterable')
961
    def visit_setcomp(self, node):
962
        for gen in node.generators:
963
            self._check_iterable(gen.iter)
964

    
965
    @check_messages('not-an-iterable')
966
    def visit_generatorexp(self, node):
967
        for gen in node.generators:
968
            self._check_iterable(gen.iter)
969

    
970

    
971
def register(linter):
972
    """required method to auto register this checker """
973
    linter.register_checker(TypeChecker(linter))
974
    linter.register_checker(IterableChecker(linter))