public override bool Walk(ReturnStatement node) { var value = Eval.GetValueFromExpression(node.Expression); if (!value.IsUnknown()) { _result = value; return(false); } return(true); }
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; } } }
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); }
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; }
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); }
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); }
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 }
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)); }
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); }
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); }
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); }