public override bool Walk(FunctionDefinition node)
        {
            // Inner function, declare as variable. Do not set variable location
            // since it is not an assignment visible to the user.
            var m = SymbolTable.Evaluate(node);

            if (m != null)
            {
                Eval.DeclareVariable(node.NameExpression.Name, m, VariableSource.Declaration, node.NameExpression);
            }
            return(false);
        }
Esempio n. 2
0
        private void ExtendAll(Node location, IPythonCollection values)
        {
            Eval.LookupNameInScopes(AllVariableName, out var scope, LookupOptions.Global);
            if (scope == null)
            {
                return;
            }

            var all    = scope.Variables[AllVariableName]?.Value as IPythonCollection;
            var list   = PythonCollectionType.CreateConcatenatedList(Module.Interpreter, all, values);
            var source = list.IsGeneric() ? VariableSource.Generic : VariableSource.Declaration;

            Eval.DeclareVariable(AllVariableName, list, source, location);
        }
Esempio n. 3
0
 private void TryHandleClassVariable(MemberExpression mex, IMember value)
 {
     if (mex.Target is NameExpression nex && nex.Name == "self")
     {
         var m   = Eval.LookupNameInScopes(nex.Name, out _, LookupOptions.Local);
         var cls = m.GetPythonType <IPythonClassType>();
         if (cls != null)
         {
             using (Eval.OpenScope(Eval.Module, cls.ClassDefinition, out _)) {
                 Eval.DeclareVariable(mex.Name, value, VariableSource.Declaration, Eval.GetLocationOfName(mex));
             }
         }
     }
 }
        public async Task HandleAnnotatedExpressionAsync(ExpressionWithAnnotation expr, IMember value, CancellationToken cancellationToken = default)
        {
            if (expr?.Annotation == null)
            {
                return;
            }

            var variableType = await Eval.GetTypeFromAnnotationAsync(expr.Annotation, cancellationToken);

            // If value is null, then this is a pure declaration like
            //   x: List[str]
            // without a value. If value is provided, then this is
            //   x: List[str] = [...]

            // Check value type for compatibility
            IMember instance = null;

            if (value != null)
            {
                var valueType = value.GetPythonType();
                if (!variableType.IsUnknown() && !valueType.Equals(variableType))
                {
                    // TODO: warn incompatible value type.
                    // TODO: verify values. Value may be list() while variable type is List[str].
                    // Leave it as variable type.
                }
                else
                {
                    instance = value;
                }
            }
            instance = instance ?? variableType?.CreateInstance(variableType.Name, Eval.GetLoc(expr.Expression), ArgumentSet.Empty) ?? Eval.UnknownType;

            if (expr.Expression is NameExpression ne)
            {
                Eval.DeclareVariable(ne.Name, instance, expr.Expression);
                return;
            }

            if (expr.Expression is MemberExpression m)
            {
                // self.x : int = 42
                var self    = Eval.LookupNameInScopes("self", out var scope);
                var argType = self?.GetPythonType();
                if (argType is PythonClassType cls && scope != null)
                {
                    cls.AddMember(m.Name, instance, true);
                }
            }
        }
Esempio n. 5
0
        public async Task HandleWithAsync(WithStatement node, CancellationToken cancellationToken = default) {
            cancellationToken.ThrowIfCancellationRequested();
            foreach (var item in node.Items.Where(x => x.Variable != null)) {
                var contextManager = await Eval.GetValueFromExpressionAsync(item.ContextManager, cancellationToken);
                var cmType = contextManager.GetPythonType();

                var enter = cmType?.GetMember(node.IsAsync ? @"__aenter__" : @"__enter__")?.GetPythonType<IPythonFunctionType>();
                if (enter != null) {
                    var context = await Eval.GetValueFromFunctionTypeAsync(enter, null, null, cancellationToken);
                    if (item.Variable is NameExpression nex && !string.IsNullOrEmpty(nex.Name)) {
                        Eval.DeclareVariable(nex.Name, context, Eval.GetLoc(item));
                    }
                }
            }
        }
        private void TryHandleClassVariable(AssignmentStatement node, IMember value)
        {
            var mex = node.Left.OfType <MemberExpression>().FirstOrDefault();

            if (!string.IsNullOrEmpty(mex?.Name) && mex.Target is NameExpression nex && nex.Name.EqualsOrdinal("self"))
            {
                var m   = Eval.LookupNameInScopes(nex.Name, out _, LookupOptions.Local);
                var cls = m.GetPythonType <IPythonClassType>();
                if (cls != null)
                {
                    using (Eval.OpenScope(Eval.Module, cls.ClassDefinition, out _)) {
                        Eval.DeclareVariable(mex.Name, value, VariableSource.Declaration, Eval.GetLocationOfName(mex));
                    }
                }
            }
        }
Esempio n. 7
0
        private void DeclareParameter(Parameter p, ParameterInfo pi)
        {
            IPythonType paramType;

            // If type is known from annotation, use it.
            if (pi != null && !pi.Type.IsUnknown() && !pi.Type.IsGenericParameter())
            {
                // TODO: technically generics may have constraints. Should we consider them?
                paramType = pi.Type;
            }
            else
            {
                paramType = pi?.DefaultValue?.GetPythonType() ?? Eval.UnknownType;
            }
            Eval.DeclareVariable(p.Name, new PythonInstance(paramType), VariableSource.Declaration, p.NameExpression);
        }
        private void AssignImportedVariables(IPythonModule module, DottedName moduleImportExpression, NameExpression asNameExpression)
        {
            // "import fob.oar as baz" is handled as
            // baz = import_module('fob.oar')
            if (asNameExpression != null)
            {
                Eval.DeclareVariable(asNameExpression.Name, module, asNameExpression);
                return;
            }

            // "import fob.oar" is handled as
            // import_module('fob.oar')
            // fob = import_module('fob')
            var importNames = moduleImportExpression.Names;

            PythonPackage pythonPackage = null;
            var           existingDepth = 0;

            var childPackage = Eval.GetInScope <PythonPackage>(importNames[0].Name);

            while (childPackage != null && existingDepth < importNames.Count - 1)
            {
                existingDepth++;
                pythonPackage = childPackage;
                childPackage  = pythonPackage.GetMember <PythonPackage>(importNames[existingDepth].Name);
            }

            var child = module;

            for (var i = importNames.Count - 2; i >= existingDepth; i--)
            {
                var childName  = importNames[i + 1].Name;
                var parentName = importNames[i].Name;
                var parent     = new PythonPackage(parentName, Eval.Services);
                parent.AddChildModule(childName, child);
                child = parent;
            }

            if (pythonPackage == null)
            {
                Eval.DeclareVariable(importNames[0].Name, child, importNames[0]);
            }
            else
            {
                pythonPackage.AddChildModule(importNames[existingDepth].Name, child);
            }
        }
Esempio n. 9
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);
        }
Esempio n. 10
0
        private void ExtendAll(Node declNode, IReadOnlyList <IMember> values)
        {
            Eval.LookupNameInScopes(AllVariableName, out var scope, LookupOptions.Normal);
            if (scope == null)
            {
                return;
            }

            var loc = Eval.GetLoc(declNode);

            var allContents = (scope.Variables[AllVariableName].Value as IPythonCollection)?.Contents;

            var list   = PythonCollectionType.CreateConcatenatedList(Module.Interpreter, loc, allContents, values);
            var source = list.IsGeneric() ? VariableSource.Generic : VariableSource.Declaration;

            Eval.DeclareVariable(AllVariableName, list, source, loc);
        }
Esempio n. 11
0
        public async Task HandleForAsync(ForStatement node, CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            var iterable = await Eval.GetValueFromExpressionAsync(node.List, cancellationToken);

            var iterator = (iterable as IPythonIterable)?.GetIterator();

            if (iterator == null)
            {
                // TODO: report that expression does not evaluate to iterable.
            }
            var value = iterator?.Next ?? Eval.UnknownType;

            switch (node.Left)
            {
            case NameExpression nex:
                // for x in y:
                Eval.DeclareVariable(nex.Name, value, Eval.GetLoc(node.Left));
                break;

            case TupleExpression tex:
                // x = [('abc', 42, True), ('abc', 23, False)]
                // for some_str, some_int, some_bool in x:
                var names = tex.Items.OfType <NameExpression>().Select(x => x.Name).ToArray();
                if (value is IPythonIterable valueIterable)
                {
                    var valueIterator = valueIterable.GetIterator();
                    foreach (var n in names)
                    {
                        Eval.DeclareVariable(n, valueIterator?.Next ?? Eval.UnknownType, Eval.GetLoc(node.Left));
                    }
                }
                else
                {
                    // TODO: report that expression yields value that does not evaluate to iterable.
                }
                break;
            }

            if (node.Body != null)
            {
                await node.Body.WalkAsync(Walker, cancellationToken);
            }
        }
        public async Task EvaluateClassAsync(CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            // Open class scope chain
            using (Eval.OpenScope(_classDef, out var outerScope)) {
                var instance = Eval.GetInScope(_classDef.Name, outerScope);
                if (!(instance?.GetPythonType() is PythonClassType classInfo))
                {
                    if (instance != null)
                    {
                        // TODO: warning that variable is already declared of a different type.
                    }
                    // May be odd case like class inside a class.
                    return;
                }

                // Evaluate inner classes, if any
                await EvaluateInnerClassesAsync(_classDef, cancellationToken);

                _class = classInfo;
                // Set bases to the class.
                var bases = new List <IPythonType>();
                foreach (var a in _classDef.Bases.Where(a => string.IsNullOrEmpty(a.Name)))
                {
                    // We cheat slightly and treat base classes as annotations.
                    var b = await Eval.GetTypeFromAnnotationAsync(a.Expression, cancellationToken);

                    if (b != null)
                    {
                        bases.Add(b.GetPythonType());
                    }
                }
                _class.SetBases(Interpreter, bases);

                // Declare __class__ variable in the scope.
                Eval.DeclareVariable("__class__", _class, _classDef);

                await ProcessClassBody(cancellationToken);
            }
        }
Esempio n. 13
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(PythonAst node)
        {
            Check.InvalidOperation(() => Ast == node, "walking wrong AST");
            _cancellationToken.ThrowIfCancellationRequested();

            // Collect basic information about classes and functions in order
            // to correctly process forward references. Does not determine
            // types yet since at this time imports or generic definitions
            // have not been processed.
            SymbolTable.Build(Eval);

            // There are cases (see typeshed datetime stub) with constructs
            //   class A:
            //      def __init__(self, x: Optional[B]): ...
            //
            //   _A = A
            //
            //   class B:
            //      def func(self, x: Optional[_A])
            //
            // so evaluation of A -> B ends up incomplete since _A is not known yet.
            // Thus, when A type is created, we need to go and evaluate all assignments
            // that might be referring to it in the right hand side.
            if (Ast.Body is SuiteStatement ste)
            {
                foreach (var statement in ste.Statements.OfType <AssignmentStatement>())
                {
                    if (statement.Left.Count == 1 && statement.Left[0] is NameExpression leftNex && statement.Right is NameExpression rightNex)
                    {
                        var m = Eval.GetInScope <IPythonClassType>(rightNex.Name);
                        if (m != null)
                        {
                            Eval.DeclareVariable(leftNex.Name, m, VariableSource.Declaration, leftNex);
                        }
                    }
                }
            }

            return(base.Walk(node));
        }
Esempio n. 15
0
        private void HandleTypedVariable(IPythonType variableType, IMember value, Expression expr)
        {
            // Check value type for compatibility
            IMember instance = null;

            if (value != null)
            {
                var valueType = value.GetPythonType();
                if (!variableType.IsUnknown() && !valueType.Equals(variableType))
                {
                    // TODO: warn incompatible value type.
                    // TODO: verify values. Value may be list() while variable type is List[str].
                    // Leave it as variable type.
                }
                else
                {
                    instance = value;
                }
            }
            var args = ArgumentSet.Empty(expr, Eval);

            instance = instance ?? variableType?.CreateInstance(args) ?? Eval.UnknownType.CreateInstance(ArgumentSet.WithoutContext);

            if (expr is NameExpression ne)
            {
                Eval.DeclareVariable(ne.Name, instance, VariableSource.Declaration, ne);
                return;
            }

            if (expr is MemberExpression m)
            {
                // self.x : int = 42
                var self    = Eval.LookupNameInScopes("self", out var scope);
                var argType = self?.GetPythonType();
                if (argType is PythonClassType cls && scope != null)
                {
                    cls.AddMember(m.Name, instance, true);
                }
            }
        }
        public void EvaluateClass()
        {
            // Open class scope chain
            using (Eval.OpenScope(Module, _classDef, out var outerScope)) {
                var instance = Eval.GetInScope(_classDef.Name, outerScope);
                if (!(instance?.GetPythonType() is PythonClassType classInfo))
                {
                    if (instance != null)
                    {
                        // TODO: warning that variable is already declared of a different type.
                    }
                    return;
                }

                // Evaluate inner classes, if any
                EvaluateInnerClasses(_classDef);

                _class = classInfo;
                // Set bases to the class.
                var bases = new List <IPythonType>();
                foreach (var a in _classDef.Bases.Where(a => string.IsNullOrEmpty(a.Name)))
                {
                    // We cheat slightly and treat base classes as annotations.
                    var b = Eval.GetTypeFromAnnotation(a.Expression);
                    if (b != null)
                    {
                        var t = b.GetPythonType();
                        bases.Add(t);
                        t.AddReference(Eval.GetLocationOfName(a.Expression));
                    }
                }
                _class.SetBases(bases);

                // Declare __class__ variable in the scope.
                Eval.DeclareVariable("__class__", _class, VariableSource.Declaration);

                ProcessClassBody();
            }
        }
        private void HandleImport(ModuleName moduleImportExpression, NameExpression asNameExpression, bool forceAbsolute)
        {
            // "import fob.oar.baz" means
            // import_module('fob')
            // import_module('fob.oar')
            // import_module('fob.oar.baz')
            var importNames = ImmutableArray <string> .Empty;
            var lastModule  = default(PythonVariableModule);
            var firstModule = default(PythonVariableModule);

            foreach (var nameExpression in moduleImportExpression.Names)
            {
                importNames = importNames.Add(nameExpression.Name);
                var imports = ModuleResolution.CurrentPathResolver.GetImportsFromAbsoluteName(Module.FilePath, importNames, forceAbsolute);
                if (!HandleImportSearchResult(imports, lastModule, asNameExpression, moduleImportExpression, out lastModule))
                {
                    lastModule = default;
                    break;
                }

                if (firstModule == default)
                {
                    firstModule = lastModule;
                }
            }

            // "import fob.oar.baz as baz" is handled as baz = import_module('fob.oar.baz')
            // "import fob.oar.baz" is handled as fob = import_module('fob')
            if (!string.IsNullOrEmpty(asNameExpression?.Name) && lastModule != default)
            {
                Eval.DeclareVariable(asNameExpression.Name, lastModule, VariableSource.Import, asNameExpression);
            }
            else if (firstModule != default && !string.IsNullOrEmpty(importNames[0]))
            {
                var firstName = moduleImportExpression.Names[0];
                Eval.DeclareVariable(importNames[0], firstModule, VariableSource.Import, firstName);
            }
        }
Esempio n. 18
0
        private async Task DeclareParameterAsync(Parameter p, int index, ParameterInfo pi, CancellationToken cancellationToken = default)
        {
            IPythonType paramType;

            // If type is known from annotation, use it.
            if (pi != null && !pi.Type.IsUnknown() && !pi.Type.IsGenericParameter())
            {
                // TODO: technically generics may have constraints. Should we consider them?
                paramType = pi.Type;
            }
            else
            {
                var defaultValue = await Eval.GetValueFromExpressionAsync(p.DefaultValue, cancellationToken) ?? Eval.UnknownType;

                paramType = defaultValue.GetPythonType();
                if (!paramType.IsUnknown())
                {
                    pi?.SetDefaultValueType(paramType);
                }
            }

            Eval.DeclareVariable(p.Name, paramType, p.NameExpression);
        }
        private void AssignVariables(FromImportStatement node, IImportSearchResult imports, PythonVariableModule variableModule)
        {
            if (variableModule == null)
            {
                return;
            }

            var names   = node.Names;
            var asNames = node.AsNames;

            if (names.Count == 1 && names[0].Name == "*")
            {
                // TODO: warn this is not a good style per
                // TODO: https://docs.python.org/3/faq/programming.html#what-are-the-best-practices-for-using-import-in-a-module
                // TODO: warn this is invalid if not in the global scope.
                HandleModuleImportStar(variableModule, imports is ImplicitPackageImport, node.StartIndex);
                return;
            }

            for (var i = 0; i < names.Count; i++)
            {
                var memberName = names[i].Name;
                if (!string.IsNullOrEmpty(memberName))
                {
                    var nameExpression = asNames[i] ?? names[i];
                    var variableName   = nameExpression?.Name ?? memberName;
                    if (!string.IsNullOrEmpty(variableName))
                    {
                        var variable = variableModule.Analysis?.GlobalScope?.Variables[memberName];
                        var exported = variable ?? variableModule.GetMember(memberName);
                        var value    = exported ?? GetValueFromImports(variableModule, imports as IImportChildrenSource, memberName);
                        // Do not allow imported variables to override local declarations
                        Eval.DeclareVariable(variableName, value, VariableSource.Import, nameExpression, CanOverwriteVariable(variableName, node.StartIndex));
                    }
                }
            }
        }
Esempio n. 20
0
        private void HandleModuleImportStar(PythonVariableModule variableModule, bool isImplicitPackage, int importPosition)
        {
            if (variableModule.Module == Module)
            {
                // from self import * won't define any new members
                return;
            }

            // If __all__ is present, take it, otherwise declare all members from the module that do not begin with an underscore.
            var memberNames = isImplicitPackage
                ? variableModule.GetMemberNames()
                : variableModule.Analysis.StarImportMemberNames ?? variableModule.GetMemberNames().Where(s => !s.StartsWithOrdinal("_"));

            foreach (var memberName in memberNames)
            {
                var member = variableModule.GetMember(memberName);
                if (member == null)
                {
                    Log?.Log(TraceEventType.Verbose, $"Undefined import: {variableModule.Name}, {memberName}");
                }
                else if (member.MemberType == PythonMemberType.Unknown)
                {
                    Log?.Log(TraceEventType.Verbose, $"Unknown import: {variableModule.Name}, {memberName}");
                }

                member = member ?? Eval.UnknownType;
                if (member is IPythonModule m)
                {
                    ModuleResolution.GetOrLoadModule(m.Name);
                }

                var variable = variableModule.Analysis?.GlobalScope?.Variables[memberName];
                // Do not allow imported variables to override local declarations
                Eval.DeclareVariable(memberName, variable ?? member, VariableSource.Import, Eval.DefaultLocation, CanOverwriteVariable(memberName, importPosition));
            }
        }
        public async Task HandleAssignmentAsync(AssignmentStatement node, CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();
            var value = await Eval.GetValueFromExpressionAsync(node.Right, cancellationToken);

            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 TupleExpression lhs)
            {
                // Tuple = Tuple. Transfer values.
                var texHandler = new TupleExpressionHandler(Walker);
                await texHandler.HandleTupleAssignmentAsync(lhs, node.Right, value, cancellationToken);

                return;
            }
            foreach (var expr in node.Left.OfType <ExpressionWithAnnotation>())
            {
                // x: List[str] = [...]
                await HandleAnnotatedExpressionAsync(expr, value, cancellationToken);
            }

            foreach (var ne in node.Left.OfType <NameExpression>())
            {
                if (Eval.CurrentScope.NonLocals[ne.Name] != null)
                {
                    Eval.LookupNameInScopes(ne.Name, out var scope, LookupOptions.Nonlocal);
                    if (scope != null)
                    {
                        scope.Variables[ne.Name].Value = value;
                    }
                    else
                    {
                        // TODO: report variable is not declared in outer scopes.
                    }
                    continue;
                }

                if (Eval.CurrentScope.Globals[ne.Name] != null)
                {
                    Eval.LookupNameInScopes(ne.Name, out var scope, LookupOptions.Global);
                    if (scope != null)
                    {
                        scope.Variables[ne.Name].Value = value;
                    }
                    else
                    {
                        // TODO: report variable is not declared in global scope.
                    }
                    continue;
                }

                Eval.DeclareVariable(ne.Name, value, Eval.GetLoc(ne));
            }
        }
Esempio n. 22
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);
        }
        /// <summary>
        /// Merges data from stub with the data from the module.
        /// </summary>
        /// <remarks>
        /// Functions are taken from the stub by the function walker since
        /// information on the return type is needed during the analysis walk.
        /// However, if the module is compiled (scraped), it often lacks some
        /// of the definitions. Stub may contains those so we need to merge it in.
        /// </remarks>
        private void MergeStub()
        {
            if (Module.ModuleType == ModuleType.User)
            {
                return;
            }
            // No stub, no merge.
            if (_stubAnalysis == null)
            {
                return;
            }

            var builtins = Module.Interpreter.ModuleResolution.BuiltinsModule;

            // Note that scrape can pick up more functions than the stub contains
            // Or the stub can have definitions that scraping had missed. Therefore
            // merge is the combination of the two with the documentation coming
            // from the library source of from the scraped module.
            foreach (var v in _stubAnalysis.GlobalScope.Variables)
            {
                var stubType = v.Value.GetPythonType();
                if (stubType.IsUnknown())
                {
                    continue;
                }

                var sourceVar  = Eval.GlobalScope.Variables[v.Name];
                var sourceType = sourceVar?.Value.GetPythonType();

                // If stub says 'Any' but we have better type, keep the current type.
                if (!IsStubBetterType(sourceType, stubType))
                {
                    continue;
                }

                // If type does not exist in module, but exists in stub, declare it unless it is an import.
                // If types are the classes, merge members. Otherwise, replace type from one from the stub.
                switch (sourceType)
                {
                case null:
                    // Nothing in sources, but there is type in the stub. Declare it.
                    if (v.Source == VariableSource.Declaration)
                    {
                        Eval.DeclareVariable(v.Name, v.Value, v.Source);
                    }
                    break;

                case PythonClassType cls when Module.Equals(cls.DeclaringModule):
                    // If class exists and belongs to this module, add or replace
                    // its members with ones from the stub, preserving documentation.
                    // Don't augment types that do not come from this module.
                    // Do not replace __class__ since it has to match class type and we are not
                    // replacing class type, we are only merging members.
                    foreach (var name in stubType.GetMemberNames().Except(new[] { "__class__", "__base__", "__bases__", "__mro__", "mro" }))
                    {
                        var stubMember = stubType.GetMember(name);
                        var member     = cls.GetMember(name);

                        var memberType     = member?.GetPythonType();
                        var stubMemberType = stubMember.GetPythonType();

                        if (builtins.Equals(memberType?.DeclaringModule) || builtins.Equals(stubMemberType?.DeclaringModule))
                        {
                            continue;     // Leave builtins alone.
                        }

                        if (memberType?.DeclaringModule is SpecializedModule || stubMemberType?.DeclaringModule is SpecializedModule)
                        {
                            continue;     // Leave specialized modules like typing alone.
                        }

                        if (!IsStubBetterType(memberType, stubMemberType))
                        {
                            continue;
                        }

                        // Get documentation from the current type, if any, since stubs
                        // typically do not contain documentation while scraped code does.
                        TransferDocumentationAndLocation(memberType, stubMemberType);
                        cls.AddMember(name, stubMember, overwrite: true);
                    }
                    break;

                case IPythonModule _:
                    // We do not re-declare modules.
                    break;

                default:
                    // Re-declare variable with the data from the stub unless member is a module.
                    // Modules members that are modules should remain as they are, i.e. os.path
                    // should remain library with its own stub attached.
                    var stubModule = stubType.DeclaringModule;
                    if (!(stubType is IPythonModule) && !builtins.Equals(stubModule))
                    {
                        TransferDocumentationAndLocation(sourceType, stubType);
                        // TODO: choose best type between the scrape and the stub. Stub probably should always win.
                        var source = Eval.CurrentScope.Variables[v.Name]?.Source ?? v.Source;
                        Eval.DeclareVariable(v.Name, v.Value, source);
                    }
                    break;
                }
            }
        }
 private void MakeUnresolvedImport(string name, Node node)
 => Eval.DeclareVariable(name, new SentinelModule(name, Eval.Services), Eval.GetLoc(node));
Esempio n. 26
0
        private async Task DeclareParametersAsync(CancellationToken cancellationToken = default)
        {
            // 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.
                    Eval.DeclareVariable(p0.Name, _self, p0.NameExpression);
                    // Set parameter info.
                    var pi = new ParameterInfo(Ast, p0, _self);
                    pi.SetType(_self);
                    parameters.Add(pi);
                    skip++;
                }
            }

            // Declare parameters in scope
            for (var i = skip; i < FunctionDefinition.Parameters.Length; i++)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var p = FunctionDefinition.Parameters[i];
                if (!string.IsNullOrEmpty(p.Name))
                {
                    // 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): ...
                    IPythonType paramType = null;
                    if (p.DefaultValue != null)
                    {
                        paramType = await Eval.GetTypeFromAnnotationAsync(p.Annotation, cancellationToken, LookupOptions.Local | LookupOptions.Builtins);

                        if (paramType == null)
                        {
                            var defaultValue = await Eval.GetValueFromExpressionAsync(p.DefaultValue, cancellationToken);

                            if (!defaultValue.IsUnknown())
                            {
                                paramType = defaultValue.GetPythonType();
                            }
                        }
                    }
                    // If all else fails, look up globally.
                    paramType = paramType ?? await Eval.GetTypeFromAnnotationAsync(p.Annotation, cancellationToken);

                    var pi = new ParameterInfo(Ast, p, paramType);
                    await DeclareParameterAsync(p, i, pi, cancellationToken);

                    parameters.Add(pi);
                }
            }
            _overload.SetParameters(parameters);
        }