Exemplo n.º 1
0
        public override bool Walk(ReturnStatement node)
        {
            var value = Eval.GetValueFromExpression(node.Expression);

            if (!value.IsUnknown())
            {
                _result = value;
                return(false);
            }
            return(true);
        }
Exemplo n.º 2
0
        public void HandleAssignment(AssignmentStatement node)
        {
            if (node.Right is ErrorExpression)
            {
                return;
            }

            var value = Eval.GetValueFromExpression(node.Right) ?? Eval.UnknownType;
            // Filter out parenthesis expression in assignment because it makes no difference.
            var lhs = node.Left.Select(s => s.RemoveParenthesis());
            // Check PEP hint first
            var valueType = Eval.GetTypeFromPepHint(node.Right);

            if (valueType != null)
            {
                HandleTypedVariable(valueType, value, lhs.FirstOrDefault());
                return;
            }

            if (value.IsUnknown())
            {
                Log?.Log(TraceEventType.Verbose, $"Undefined value: {node.Right.ToCodeString(Ast).Trim()}");
            }
            if (value?.GetPythonType().TypeId == BuiltinTypeId.Ellipsis)
            {
                value = Eval.UnknownType;
            }

            foreach (var expr in lhs)
            {
                switch (expr)
                {
                case SequenceExpression seq:
                    // Tuple = Tuple. Transfer values.
                    var seqHandler = new SequenceExpressionHandler(Walker);
                    seqHandler.HandleAssignment(seq, value);
                    break;

                case ExpressionWithAnnotation annExpr:
                    HandleAnnotatedExpression(annExpr, value);
                    break;

                case NameExpression nameExpr:
                    HandleNameExpression(nameExpr, value);
                    break;

                case MemberExpression memberExpr:
                    TryHandleClassVariable(memberExpr, value);
                    break;
                }
            }
        }
Exemplo n.º 3
0
        private void HandleAllAppendExtend(CallExpression node)
        {
            if (!(node.Target is MemberExpression me))
            {
                return;
            }

            if (!IsHandleableAll(me.Target))
            {
                return;
            }

            if (node.Args.Count == 0)
            {
                return;
            }

            var arg = node.Args[0].Expression;
            var v   = Eval.GetValueFromExpression(arg);

            if (v == null)
            {
                _allIsUsable = false;
                return;
            }

            IPythonCollection values = null;

            switch (me.Name)
            {
            case "append":
                values = PythonCollectionType.CreateList(Module.Interpreter, Eval.GetLoc(arg), new List <IMember>()
                {
                    v
                }, exact: true);
                break;

            case "extend":
                values = v as IPythonCollection;
                break;
            }

            if (values == null)
            {
                _allIsUsable = false;
                return;
            }

            ExtendAll(node, values);
        }
Exemplo n.º 4
0
        public override void Evaluate()
        {
            var stub = SymbolTable.ReplacedByStubs.Contains(Target) ||
                       _function.DeclaringModule.ModuleType == ModuleType.Stub ||
                       Module.ModuleType == ModuleType.Specialized;

            using (Eval.OpenScope(_function.DeclaringModule, FunctionDefinition, out _)) {
                // Process annotations.
                var annotationType = Eval.GetTypeFromAnnotation(FunctionDefinition.ReturnAnnotation);
                if (!annotationType.IsUnknown())
                {
                    // Annotations are typically types while actually functions return
                    // instances unless specifically annotated to a type such as Type[T].
                    var instance = annotationType.CreateInstance(annotationType.Name, ArgumentSet.Empty);
                    _overload.SetReturnValue(instance, true);
                }
                else
                {
                    // Check if function is a generator
                    var suite     = FunctionDefinition.Body as SuiteStatement;
                    var yieldExpr = suite?.Statements.OfType <ExpressionStatement>().Select(s => s.Expression as YieldExpression).ExcludeDefault().FirstOrDefault();
                    if (yieldExpr != null)
                    {
                        // Function return is an iterator
                        var yieldValue  = Eval.GetValueFromExpression(yieldExpr.Expression) ?? Eval.UnknownType;
                        var returnValue = new PythonGenerator(Eval.Interpreter, yieldValue);
                        _overload.SetReturnValue(returnValue, true);
                    }
                }

                DeclareParameters(!stub);

                // Do process body of constructors since they may be declaring
                // variables that are later used to determine return type of other
                // methods and properties.
                var ctor = _function.Name.EqualsOrdinal("__init__") || _function.Name.EqualsOrdinal("__new__");
                if (ctor || annotationType.IsUnknown() || Module.ModuleType == ModuleType.User)
                {
                    // Return type from the annotation is sufficient for libraries and stubs, no need to walk the body.
                    FunctionDefinition.Body?.Walk(this);
                    // For libraries remove declared local function variables to free up some memory.
                    var optionsProvider = Eval.Services.GetService <IAnalysisOptionsProvider>();
                    if (Module.ModuleType != ModuleType.User && optionsProvider?.Options.KeepLibraryLocalVariables != true)
                    {
                        ((VariableCollection)Eval.CurrentScope.Variables).Clear();
                    }
                }
            }
            Result = _function;
        }
Exemplo n.º 5
0
        private void HandleAllAppendExtend(CallExpression node)
        {
            if (!(node.Target is MemberExpression me))
            {
                return;
            }

            if (!IsHandleableAll(me.Target))
            {
                return;
            }

            if (node.Args.Count == 0)
            {
                return;
            }

            IReadOnlyList <IMember> contents = null;
            var v = Eval.GetValueFromExpression(node.Args[0].Expression);

            if (v == null)
            {
                _allIsUsable = false;
                return;
            }

            switch (me.Name)
            {
            case "append":
                contents = new List <IMember>()
                {
                    v
                };
                break;

            case "extend":
                contents = (v as IPythonCollection)?.Contents;
                break;
            }

            if (contents == null)
            {
                _allIsUsable = false;
                return;
            }

            ExtendAll(node, contents);
        }
Exemplo n.º 6
0
        public bool HandleTryExcept(TryStatement node)
        {
            node.Body.Walk(Walker);
            foreach (var handler in node.Handlers.MaybeEnumerate())
            {
                if (handler.Test != null && handler.Target is NameExpression nex)
                {
                    var value = Eval.GetValueFromExpression(handler.Test);
                    Eval.DeclareVariable(nex.Name, value ?? Eval.UnknownType, VariableSource.Declaration, nex);
                }
                handler.Body.Walk(Walker);
            }

            node.Finally?.Walk(Walker);
            node.Else?.Walk(Walker);
            return(false);
        }
Exemplo n.º 7
0
        public void HandleWith(WithStatement node)
        {
            foreach (var item in node.Items.Where(x => x.Variable != null))
            {
                var     contextManager = Eval.GetValueFromExpression(item.ContextManager);
                var     cmType         = contextManager?.GetPythonType();
                IMember context        = Eval.UnknownType;

                var enter = cmType?.GetMember(node.IsAsync ? @"__aenter__" : @"__enter__")?.GetPythonType <IPythonFunctionType>();
                if (enter != null)
                {
                    var instance = contextManager as IPythonInstance;
                    var callExpr = item.ContextManager as CallExpression;
                    context = Eval.GetValueFromFunctionType(enter, instance, callExpr);
                    // If fetching context from __enter__ failed, annotation in the stub may be using
                    // type from typing that we haven't specialized yet or there may be an issue in
                    // the stub itself, such as type or incorrect type. Try using context manager then.
                    context = context.IsUnknown() ? contextManager : context;
                }

                switch (item.Variable)
                {
                // Handle with Test() as a
                case NameExpression nameExpr when !string.IsNullOrEmpty(nameExpr.Name):
                    Eval.DeclareVariable(nameExpr.Name, context, VariableSource.Declaration, item);
                    break;

                // Handle with Test() as (a)
                case ParenthesisExpression parExpr when parExpr.Expression is NameExpression nameExpr && !string.IsNullOrEmpty(nameExpr.Name):
                    Eval.DeclareVariable(nameExpr.Name, context, VariableSource.Declaration, item);
                    break;

                // Handle with Test() as (a, b)
                // Single element list [a] is a sequence expression so also handled here
                case SequenceExpression seqExpr:
                    var sequenceHandler = new SequenceExpressionHandler(Walker);
                    sequenceHandler.HandleAssignment(seqExpr, context);
                    break;
                }
            }
        }
        public override bool Walk(ReturnStatement node)
        {
            var value = Eval.GetValueFromExpression(node.Expression);

            if (value != null)
            {
                // although technically legal, __init__ in a constructor should not have a not-none return value
                if (_function.IsDunderInit() && !value.IsOfType(BuiltinTypeId.None))
                {
                    Eval.ReportDiagnostics(Module.Uri, new DiagnosticsEntry(
                                               Resources.ReturnInInit,
                                               node.GetLocation(Eval).Span,
                                               ErrorCodes.ReturnInInit,
                                               Severity.Warning,
                                               DiagnosticSource.Analysis));
                }

                _overload.AddReturnValue(value);
            }
            return(true); // We want to evaluate all code so all private variables in __new__ get defined
        }
Exemplo n.º 9
0
        public override bool Walk(AssignmentStatement node)
        {
            var value = Eval.GetValueFromExpression(node.Right) ?? Eval.UnknownType;

            foreach (var lhs in node.Left)
            {
                switch (lhs)
                {
                case MemberExpression memberExp when memberExp.Target is NameExpression nameExp1: {
                    if (_function.DeclaringType.GetPythonType() is PythonClassType t && nameExp1.Name == "self")
                    {
                        t.AddMembers(new[] { new KeyValuePair <string, IMember>(memberExp.Name, value) }, false);
                    }
                    continue;
                }

                case NameExpression nameExp2 when nameExp2.Name == "self":
                    return(true);    // Don't assign to 'self'
                }
            }
            return(base.Walk(node));
        }
Exemplo n.º 10
0
        private IMember GetArgumentValue(Argument arg)
        {
            if (arg.Value is IMember m)
            {
                return(m);
            }
            // Evaluates expression in the specific module context. Typically used to evaluate
            // expressions representing default values of function arguments since they are
            // are defined in the function declaring module rather than in the caller context.
            if (arg.ValueExpression == null)
            {
                return(Eval.UnknownType);
            }

            if (arg.ValueIsDefault)
            {
                using (Eval.OpenScope(DeclaringModule.Analysis.GlobalScope)) {
                    return(Eval.GetValueFromExpression(arg.ValueExpression) ?? Eval.UnknownType);
                }
            }
            return(Eval.GetValueFromExpression(arg.ValueExpression) ?? Eval.UnknownType);
        }
Exemplo n.º 11
0
        private IMember ExtractRhs(Expression rhs, Expression typed, LookupOptions lookupOptions = LookupOptions.Normal)
        {
            var value = Eval.GetValueFromExpression(rhs, lookupOptions) ?? Eval.UnknownType;

            // Check PEP hint first
            var valueType = Eval.GetTypeFromPepHint(rhs);

            if (valueType != null)
            {
                HandleTypedVariable(valueType, value, typed);
                return(null);
            }

            if (value.IsUnknown())
            {
                Log?.Log(TraceEventType.Verbose, $"Undefined value: {rhs.ToCodeString(Ast).Trim()}");
            }
            if (value?.GetPythonType().TypeId == BuiltinTypeId.Ellipsis)
            {
                value = Eval.UnknownType;
            }

            return(value);
        }
Exemplo n.º 12
0
        private void DeclareParameters(bool declareVariables)
        {
            // For class method no need to add extra parameters, but first parameter type should be the class.
            // For static and unbound methods do not add or set anything.
            // For regular bound methods add first parameter and set it to the class.

            var parameters = new List <ParameterInfo>();
            var skip       = 0;

            if (_self != null && _function.HasClassFirstArgument())
            {
                var p0 = FunctionDefinition.Parameters.FirstOrDefault();
                if (p0 != null && !string.IsNullOrEmpty(p0.Name))
                {
                    // Actual parameter type will be determined when method is invoked.
                    // The reason is that if method might be called on a derived class.
                    // Declare self or cls in this scope.
                    if (declareVariables)
                    {
                        Eval.DeclareVariable(p0.Name, new PythonInstance(_self), VariableSource.Declaration, p0.NameExpression);
                    }
                    // Set parameter info.
                    var pi = new ParameterInfo(Ast, p0, _self, null, false);
                    parameters.Add(pi);
                    skip++;
                }
            }

            // Declare parameters in scope
            IMember defaultValue = null;

            for (var i = skip; i < FunctionDefinition.Parameters.Length; i++)
            {
                var isGeneric = false;
                var p         = FunctionDefinition.Parameters[i];
                if (!string.IsNullOrEmpty(p.Name))
                {
                    IPythonType paramType = null;
                    if (p.DefaultValue != null)
                    {
                        defaultValue = Eval.GetValueFromExpression(p.DefaultValue);
                        // If parameter has default value, look for the annotation locally first
                        // since outer type may be getting redefined. Consider 's = None; def f(s: s = 123): ...
                        paramType = Eval.GetTypeFromAnnotation(p.Annotation, out isGeneric, LookupOptions.Local | LookupOptions.Builtins);
                        // Default value of None does not mean the parameter is None, just says it can be missing.
                        defaultValue = defaultValue.IsUnknown() || defaultValue.IsOfType(BuiltinTypeId.NoneType) ? null : defaultValue;
                        if (paramType == null && defaultValue != null)
                        {
                            paramType = defaultValue.GetPythonType();
                        }
                    }
                    // If all else fails, look up globally.
                    paramType = paramType ?? Eval.GetTypeFromAnnotation(p.Annotation, out isGeneric) ?? Eval.UnknownType;
                    var pi = new ParameterInfo(Ast, p, paramType, defaultValue, isGeneric);
                    if (declareVariables)
                    {
                        DeclareParameter(p, pi);
                    }
                    parameters.Add(pi);
                }
            }
            _overload.SetParameters(parameters);
        }
        public void HandleAssignment(AssignmentStatement node)
        {
            if (node.Right is ErrorExpression)
            {
                return;
            }

            var value = Eval.GetValueFromExpression(node.Right) ?? Eval.UnknownType;
            // Check PEP hint first
            var valueType = Eval.GetTypeFromPepHint(node.Right);

            if (valueType != null)
            {
                HandleTypedVariable(valueType, value, node.Left.FirstOrDefault());
                return;
            }

            if (value.IsUnknown())
            {
                Log?.Log(TraceEventType.Verbose, $"Undefined value: {node.Right.ToCodeString(Ast).Trim()}");
            }
            if (value?.GetPythonType().TypeId == BuiltinTypeId.Ellipsis)
            {
                value = Eval.UnknownType;
            }

            if (node.Left.FirstOrDefault() is SequenceExpression seq)
            {
                // Tuple = Tuple. Transfer values.
                var seqHandler = new SequenceExpressionHandler(Walker);
                seqHandler.HandleAssignment(seq.Items, node.Right, value);
                return;
            }

            // Process annotations, if any.
            foreach (var expr in node.Left.OfType <ExpressionWithAnnotation>())
            {
                // x: List[str] = [...]
                HandleAnnotatedExpression(expr, value);
            }

            foreach (var ne in node.Left.OfType <NameExpression>())
            {
                if (Eval.CurrentScope.NonLocals[ne.Name] != null)
                {
                    Eval.LookupNameInScopes(ne.Name, out var scope, LookupOptions.Nonlocal);
                    scope?.Variables[ne.Name].Assign(value, Eval.GetLocationOfName(ne));
                    continue;
                }

                if (Eval.CurrentScope.Globals[ne.Name] != null)
                {
                    Eval.LookupNameInScopes(ne.Name, out var scope, LookupOptions.Global);
                    scope?.Variables[ne.Name].Assign(value, Eval.GetLocationOfName(ne));
                    continue;
                }

                var source   = value.IsGeneric() ? VariableSource.Generic : VariableSource.Declaration;
                var location = Eval.GetLocationOfName(ne);
                if (IsValidAssignment(ne.Name, location))
                {
                    Eval.DeclareVariable(ne.Name, value ?? Module.Interpreter.UnknownType, source, location);
                }
            }

            TryHandleClassVariable(node, value);
        }