def addMembersFromMethod(self, method) : if not hasattr(method, 'func_code') : return func_code, code, i, maxCode, extended_arg = OP.initFuncCode(method) stack = [] while i < maxCode : op, oparg, i, extended_arg = OP.getInfo(code, i, extended_arg) if op >= OP.HAVE_ARGUMENT : operand = OP.getOperand(op, func_code, oparg) if OP.LOAD_CONST(op) or OP.LOAD_FAST(op) or OP.LOAD_GLOBAL(op): stack.append(operand) elif OP.LOAD_DEREF(op): try: operand = func_code.co_cellvars[oparg] except IndexError: index = oparg - len(func_code.co_cellvars) operand = func_code.co_freevars[index] stack.append(operand) elif OP.STORE_ATTR(op) : if len(stack) > 0 : if stack[-1] == utils.cfg().methodArgName: value = None if len(stack) > 1 : value = type(stack[-2]) self.members[operand] = value self.memberRefs[operand] = None stack = [] self.cleanupMemberRefs()
def addMembersFromMethod(self, method): if not hasattr(method, 'func_code'): return func_code, code, i, maxCode, extended_arg = OP.initFuncCode(method) stack = [] while i < maxCode: op, oparg, i, extended_arg = OP.getInfo(code, i, extended_arg) if op >= OP.HAVE_ARGUMENT: operand = OP.getOperand(op, func_code, oparg) if OP.LOAD_CONST(op) or OP.LOAD_FAST(op) or OP.LOAD_GLOBAL(op): stack.append(operand) elif OP.LOAD_DEREF(op): try: operand = func_code.co_cellvars[oparg] except IndexError: index = oparg - len(func_code.co_cellvars) operand = func_code.co_freevars[index] stack.append(operand) elif OP.STORE_ATTR(op): if len(stack) > 0: if stack[-1] == cfg().methodArgName: value = None if len(stack) > 1: value = type(stack[-2]) self.members[operand] = value self.memberRefs[operand] = None stack = [] self.cleanupMemberRefs()
def _findUnreachableCode(code) : # code after RETURN or RAISE is unreachable unless there's a branch to it unreachable = {} terminals = code.returnValues[:-1] + code.raiseValues terminals.sort(lambda a, b: cmp(a[2], b[2])) for line, dummy, i in terminals : if not code.branches.has_key(i) : unreachable[i] = line # find the index of the last return lastLine = lastItem = lastIndex = None if code.returnValues: lastLine, lastItem, lastIndex = code.returnValues[-1] if len(code.returnValues) >= 2 : lastIndex = code.returnValues[-2][2] if code.raiseValues : lastIndex = max(lastIndex, code.raiseValues[-1][2]) # remove last return if it's unreachable AND implicit if unreachable.get(lastIndex) == lastLine and lastItem and \ lastItem.isImplicitNone(): del code.returnValues[-1] del unreachable[lastIndex] if cfg().unreachableCode : for index in unreachable.keys() : try : if not OP.JUMP_FORWARD(ord(code.bytes[index])) : code.addWarning(msgs.CODE_UNREACHABLE, unreachable[index]) except IndexError : pass
def abstractMethod(self, m): """Return 1 if method is abstract, None if not An abstract method always raises an exception. """ if not self.methods.get(m, None): return None func_code, bytes, i, maxCode, extended_arg = \ OP.initFuncCode(self.methods[m].function) # abstract if the first conditional is RAISE_VARARGS while i < maxCode: op, oparg, i, extended_arg = OP.getInfo(bytes, i, extended_arg) if OP.RAISE_VARARGS(op): return 1 if OP.conditional(op): break return None
def abstractMethod(self, m): """Return 1 if method is abstract, None if not An abstract method always raises an exception. """ if not self.methods.get(m, None): return None func_code, bytes, i, maxCode, extended_arg = OP.initFuncCode(self.methods[m].function) # abstract if the first opcode is RAISE_VARARGS and it raises # NotImplementedError arg = "" while i < maxCode: op, oparg, i, extended_arg = OP.getInfo(bytes, i, extended_arg) if OP.LOAD_GLOBAL(op): arg = func_code.co_names[oparg] elif OP.RAISE_VARARGS(op): # if we saw NotImplementedError sometime before the raise # assume it's related to this raise stmt return arg == "NotImplementedError" if OP.conditional(op): break return None
def abstractMethod(self, m): """Return 1 if method is abstract, None if not An abstract method always raises an exception. """ if not self.methods.get(m, None): return None func_code, bytes, i, maxCode, extended_arg = \ OP.initFuncCode(self.methods[m].function) # abstract if the first opcode is RAISE_VARARGS and it raises # NotImplementedError arg = "" while i < maxCode: op, oparg, i, extended_arg = OP.getInfo(bytes, i, extended_arg) if OP.LOAD_GLOBAL(op): arg = func_code.co_names[oparg] elif OP.RAISE_VARARGS(op): # if we saw NotImplementedError sometime before the raise # assume it's related to this raise stmt return arg == "NotImplementedError" if OP.conditional(op): break return None
def addMembersFromMethod(self, method) : if not hasattr(method, 'func_code') : return func_code, code, i, maxCode, extended_arg = OP.initFuncCode(method) stack = [] while i < maxCode : op, oparg, i, extended_arg = OP.getInfo(code, i, extended_arg) if op >= OP.HAVE_ARGUMENT : operand = OP.getOperand(op, func_code, oparg) if OP.LOAD_CONST(op) or OP.LOAD_FAST(op) : stack.append(operand) elif OP.STORE_ATTR(op) : if len(stack) > 0 : if stack[-1] == cfg().methodArgName: value = None if len(stack) > 1 : value = type(stack[-2]) self.members[operand] = value self.memberRefs[operand] = None stack = [] self.cleanupMemberRefs()
def _checkFunction(module, func, c = None, main = 0, in_class = 0) : """ Return a list of Warnings found in a function/method. @type module: L{pychecker.checker.PyCheckerModule} """ # always push a new config object, so we can pop at end of function utils.pushConfig() code = CodeChecks.Code() code.init(func) if main: for key in func.function.func_globals.keys(): code.unusedLocals[key] = -1 codeSource = CodeChecks.CodeSource(module, func, c, main, in_class, code) try : _checkCode(code, codeSource) if not in_class : _findUnreachableCode(code) # handle lambdas and nested functions codeSource.calling_code.append(func) for key in code.codeOrder: func_code = code.codeObjects[key] _handleNestedCode(func_code, code, codeSource) del codeSource.calling_code[-1] except (SystemExit, KeyboardInterrupt) : exc_type, exc_value, exc_tb = sys.exc_info() raise exc_type, exc_value except : exc_type, exc_value, exc_tb = sys.exc_info() exc_list = traceback.format_exception(exc_type, exc_value, exc_tb) for index in range(0, len(exc_list)) : exc_list[index] = string.replace(exc_list[index], "\n", "\n\t") code.addWarning(msgs.CHECKER_BROKEN % string.join(exc_list, "")) if cfg().checkReturnValues : _checkReturnWarnings(code) if cfg().localVariablesUsed : for var, line in code.unusedLocals.items() : if line is not None and line > 0 and _name_unused(var) : code.addWarning(msgs.UNUSED_LOCAL % var, line) if cfg().argumentsUsed : op = code.getFirstOp() if not (OP.RAISE_VARARGS(op) or OP.RETURN_VALUE(op)) : for var, line in code.unusedLocals.items() : _checkUnusedParam(var, line, func, code) # Check code complexity: # loops should be counted as one branch, but there are typically 3 # branches in byte code to setup a loop, so subtract off 2/3's of them # / 2 to approximate real branches branches = (len(code.branches.keys()) - (2 * code.loops)) / 2 lines = (code.getLineNum() - code.func_code.co_firstlineno) returns = len(code.returnValues) if not main and not in_class : args = code.func_code.co_argcount localCount = len(code.func_code.co_varnames) - args _checkComplex(code, cfg().maxArgs, args, func, msgs.TOO_MANY_ARGS) _checkComplex(code, cfg().maxLocals, localCount, func, msgs.TOO_MANY_LOCALS) _checkComplex(code, cfg().maxLines, lines, func, msgs.FUNC_TOO_LONG) _checkComplex(code, cfg().maxReturns, returns, func, msgs.TOO_MANY_RETURNS) _checkComplex(code, cfg().maxBranches, branches, func, msgs.TOO_MANY_BRANCHES) if not (main or in_class) : utils.popConfig() func.returnValues = code.returnValues # FIXME: I don't think code.codeObjects.values() ever gets used, # but if it does, and needs to be in order, then use code.codeOrder here. return (code.warnings, code.globalRefs, code.functionsCalled, code.codeObjects.values(), code.returnValues)