Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes308downloads
TypeInferenceVisitor.cs3339 linesDownload Raw Back to parser
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections;5using System.Collections.Generic;6using System.Globalization;7using System.Linq;8using System.Management.Automation.Language;9using System.Management.Automation.Runspaces;10using System.Reflection;11using System.Text;12using System.Text.RegularExpressions;13 14using Microsoft.PowerShell.Commands;15 16using CimClass = Microsoft.Management.Infrastructure.CimClass;17using CimInstance = Microsoft.Management.Infrastructure.CimInstance;18 19namespace System.Management.Automation20{21    /// <summary>22    /// Enum describing permissions to use runtime evaluation during type inference.23    /// </summary>24    public enum TypeInferenceRuntimePermissions25    {26        /// <summary>27        /// No runtime use is allowed.28        /// </summary>29        None = 0,30 31        /// <summary>32        /// Use of SafeExprEvaluator visitor is allowed.33        /// </summary>34        AllowSafeEval = 1,35    }36 37    /// <summary>38    /// Static class containing methods to work with type inference of abstract syntax trees.39    /// </summary>40    internal static class AstTypeInference41    {42        /// <summary>43        /// Infers the type that the result of executing a statement would have without using runtime safe eval.44        /// </summary>45        /// <param name="ast">The ast to infer the type from.</param>46        /// <returns>List of inferred typenames.</returns>47        public static IList<PSTypeName> InferTypeOf(Ast ast)48        {49            return InferTypeOf(ast, TypeInferenceRuntimePermissions.None);50        }51 52        /// <summary>53        /// Infers the type that the result of executing a statement would have.54        /// </summary>55        /// <param name="ast">The ast to infer the type from.</param>56        /// <param name="evalPermissions">The runtime usage permissions allowed during type inference.</param>57        /// <returns>List of inferred typenames.</returns>58        public static IList<PSTypeName> InferTypeOf(Ast ast, TypeInferenceRuntimePermissions evalPermissions)59        {60            return InferTypeOf(ast, PowerShell.Create(RunspaceMode.CurrentRunspace), evalPermissions);61        }62 63        /// <summary>64        /// Infers the type that the result of executing a statement would have without using runtime safe eval.65        /// </summary>66        /// <param name="ast">The ast to infer the type from.</param>67        /// <param name="powerShell">The instance of powershell to use for expression evaluation needed for type inference.</param>68        /// <returns>List of inferred typenames.</returns>69        public static IList<PSTypeName> InferTypeOf(Ast ast, PowerShell powerShell)70        {71            return InferTypeOf(ast, powerShell, TypeInferenceRuntimePermissions.None);72        }73 74        /// <summary>75        /// Infers the type that the result of executing a statement would have.76        /// </summary>77        /// <param name="ast">The ast to infer the type from.</param>78        /// <param name="powerShell">The instance of powershell to user for expression evaluation needed for type inference.</param>79        /// <param name="evalPersmissions">The runtime usage permissions allowed during type inference.</param>80        /// <returns>List of inferred typenames.</returns>81        public static IList<PSTypeName> InferTypeOf(Ast ast, PowerShell powerShell, TypeInferenceRuntimePermissions evalPersmissions)82        {83            var context = new TypeInferenceContext(powerShell);84            return InferTypeOf(ast, context, evalPersmissions);85        }86 87        /// <summary>88        /// Infers the type that the result of executing a statement would have.89        /// </summary>90        /// <param name="ast">The ast to infer the type from.</param>91        /// <param name="context">The current type inference context.</param>92        /// <param name="evalPersmissions">The runtime usage permissions allowed during type inference.</param>93        /// <returns>List of inferred typenames.</returns>94        internal static IList<PSTypeName> InferTypeOf(95            Ast ast,96            TypeInferenceContext context,97            TypeInferenceRuntimePermissions evalPersmissions = TypeInferenceRuntimePermissions.None)98        {99            var originalRuntimePermissions = context.RuntimePermissions;100            try101            {102                context.RuntimePermissions = evalPersmissions;103                return context.InferType(ast, new TypeInferenceVisitor(context)).Distinct(new PSTypeNameComparer()).ToList();104            }105            finally106            {107                context.RuntimePermissions = originalRuntimePermissions;108            }109        }110    }111 112    internal class PSTypeNameComparer : IEqualityComparer<PSTypeName>113    {114        public bool Equals(PSTypeName x, PSTypeName y)115        {116            return x.Name.Equals(y.Name);117        }118 119        public int GetHashCode(PSTypeName obj)120        {121            return obj.Name.GetHashCode();122        }123    }124 125    internal class TypeInferenceContext126    {127        public static readonly PSTypeName[] EmptyPSTypeNameArray = Array.Empty<PSTypeName>();128        private readonly PowerShell _powerShell;129 130        public TypeInferenceContext() : this(PowerShell.Create(RunspaceMode.CurrentRunspace))131        {132        }133 134        /// <summary>135        /// Initializes a new instance of the <see cref="TypeInferenceContext"/> class.136        /// The powerShell instance passed need to have a non null Runspace.137        /// </summary>138        /// <param name="powerShell">The instance of powershell to use for expression evaluation needed for type inference.</param>139        public TypeInferenceContext(PowerShell powerShell)140        {141            Diagnostics.Assert(powerShell.Runspace != null, "Callers are required to ensure we have a runspace");142            _powerShell = powerShell;143 144            Helper = new PowerShellExecutionHelper(powerShell);145        }146 147        // used to infer types in script properties attached to an object,148        // to be able to determine the type of $this in the scripts properties149        public PSTypeName CurrentThisType { get; set; }150 151        public TypeDefinitionAst CurrentTypeDefinitionAst { get; set; }152 153        public HashSet<IParameterMetadataProvider> AnalyzedCommands { get; } = new HashSet<IParameterMetadataProvider>();154 155        public TypeInferenceRuntimePermissions RuntimePermissions { get; set; }156 157        internal PowerShellExecutionHelper Helper { get; }158 159        internal ExecutionContext ExecutionContext => _powerShell.Runspace.ExecutionContext;160 161        public bool TryGetRepresentativeTypeNameFromExpressionSafeEval(ExpressionAst expression, out PSTypeName typeName)162        {163            typeName = null;164            if (RuntimePermissions != TypeInferenceRuntimePermissions.AllowSafeEval)165            {166                return false;167            }168 169            return expression != null &&170                   SafeExprEvaluator.TrySafeEval(expression, ExecutionContext, out var value) &&171                   TryGetRepresentativeTypeNameFromValue(value, out typeName);172        }173 174        internal IList<object> GetMembersByInferredType(PSTypeName typename, bool isStatic, Func<object, bool> filter)175        {176            List<object> results = new List<object>();177 178            Func<object, bool> filterToCall = filter;179            if (typename is PSSyntheticTypeName synthetic)180            {181                foreach (var mem in synthetic.Members)182                {183                    results.Add(new PSInferredProperty(mem.Name, mem.PSTypeName));184                }185            }186 187            if (typename.Type != null)188            {189                AddMembersByInferredTypesClrType(typename, isStatic, filter, filterToCall, results);190            }191            else if (typename.TypeDefinitionAst != null)192            {193                AddMembersByInferredTypeDefinitionAst(typename, isStatic, filter, filterToCall, results);194            }195            else196            {197                // Look in the type table first.198                if (!isStatic)199                {200                    // The Ciminstance type adapter adds the full typename with and without a namespace to the list of type names.201                    // So if we see one with a full typename we need to also get the types for the short version.202                    // For example: "CimInstance#root/standardcimv2/MSFT_NetFirewallRule" and "CimInstance#MSFT_NetFirewallRule"203                    int namespaceSeparator = typename.Name.LastIndexOf('/');204                    ConsolidatedString consolidatedString;205                    if (namespaceSeparator != -1206                        && typename.Name.StartsWith("Microsoft.Management.Infrastructure.CimInstance#", StringComparison.OrdinalIgnoreCase))207                    {208                        consolidatedString = new ConsolidatedString(new[]209                        {210                            typename.Name,211                            string.Concat("Microsoft.Management.Infrastructure.CimInstance#", typename.Name.AsSpan(namespaceSeparator + 1))212                        });213                    }214                    else215                    {216                        consolidatedString = new ConsolidatedString(new[] { typename.Name });217                    }218 219                    results.AddRange(ExecutionContext.TypeTable.GetMembers<PSMemberInfo>(consolidatedString));220                }221 222                AddMembersByInferredTypeCimType(typename, results, filterToCall);223            }224 225            return results;226        }227 228        internal void AddMembersByInferredTypesClrType(PSTypeName typename, bool isStatic, Func<object, bool> filter, Func<object, bool> filterToCall, List<object> results)229        {230            if (CurrentTypeDefinitionAst == null || CurrentTypeDefinitionAst.Type != typename.Type)231            {232                if (filterToCall == null)233                {234                    filterToCall = o => !IsMemberHidden(o);235                }236                else237                {238                    filterToCall = o => !IsMemberHidden(o) && filter(o);239                }240            }241 242            IEnumerable<Type> elementTypes;243            if (typename.Type.IsArray)244            {245                elementTypes = new[] { typename.Type.GetElementType() };246            }247            else248            {249                var elementList = new List<Type>();250                foreach (var t in typename.Type.GetInterfaces())251                {252                    if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>))253                    {254                        elementList.Add(t);255                    }256                }257 258                elementTypes = elementList;259            }260 261            foreach (var type in elementTypes.Prepend(typename.Type))262            {263                // Look in the type table first.264                if (!isStatic)265                {266                    var consolidatedString = DotNetAdapter.GetInternedTypeNameHierarchy(type);267                    results.AddRange(ExecutionContext.TypeTable.GetMembers<PSMemberInfo>(consolidatedString));268                }269 270                var members = isStatic271                              ? PSObject.DotNetStaticAdapter.BaseGetMembers<PSMemberInfo>(type)272                              : PSObject.DotNetInstanceAdapter.GetPropertiesAndMethods(type, false);273 274                if (filterToCall != null)275                {276                    foreach (var member in members)277                    {278                        if (filterToCall(member))279                        {280                            results.Add(member);281                        }282                    }283                }284                else285                {286                    results.AddRange(members);287                }288            }289        }290 291        internal void AddMembersByInferredTypeDefinitionAst(292            PSTypeName typename,293            bool isStatic,294            Func<object, bool> filter,295            Func<object, bool> filterToCall,296            List<object> results)297        {298            if (CurrentTypeDefinitionAst != typename.TypeDefinitionAst)299            {300                if (filterToCall == null)301                {302                    filterToCall = o => !IsMemberHidden(o);303                }304                else305                {306                    filterToCall = o => !IsMemberHidden(o) && filter(o);307                }308            }309 310            bool foundConstructor = false;311            foreach (var member in typename.TypeDefinitionAst.Members)312            {313                bool add;314                if (member is PropertyMemberAst propertyMember)315                {316                    add = propertyMember.IsStatic == isStatic;317                }318                else319                {320                    var functionMember = (FunctionMemberAst)member;321                    add = (functionMember.IsConstructor && isStatic) || (!functionMember.IsConstructor && functionMember.IsStatic == isStatic);322                    foundConstructor |= functionMember.IsConstructor;323                }324 325                if (filterToCall != null && add)326                {327                    add = filterToCall(member);328                }329 330                if (add)331                {332                    results.Add(member);333                }334            }335 336            // iterate through bases/interfaces337            foreach (var baseType in typename.TypeDefinitionAst.BaseTypes)338            {339                if (!(baseType.TypeName is TypeName baseTypeName))340                {341                    continue;342                }343 344                var baseTypeDefinitionAst = baseTypeName._typeDefinitionAst;345                if (baseTypeDefinitionAst is null)346                {347                    var baseReflectionType = baseTypeName.GetReflectionType();348                    if (baseReflectionType is not null)349                    {350                        results.AddRange(GetMembersByInferredType(new PSTypeName(baseReflectionType), isStatic, filterToCall));351                    }352                }353                else354                {355                    results.AddRange(GetMembersByInferredType(new PSTypeName(baseTypeDefinitionAst), isStatic, filterToCall));356                }357            }358 359            // Add stuff from our base class System.Object.360            if (isStatic)361            {362                // Don't add base class constructors363                if (filter == null)364                {365                    filterToCall = o => !IsConstructor(o);366                }367                else368                {369                    filterToCall = o => !IsConstructor(o) && filter(o);370                }371 372                if (!foundConstructor)373                {374                    results.Add(375                        new CompilerGeneratedMemberFunctionAst(376                            PositionUtilities.EmptyExtent,377                            typename.TypeDefinitionAst,378                            SpecialMemberFunctionType.DefaultConstructor));379                }380            }381            else382            {383                // Reset the filter because the recursive call will add IsHidden back if necessary.384                filterToCall = filter;385            }386 387            PSTypeName baseMembersType;388            if (typename.TypeDefinitionAst.IsEnum)389            {390                if (!isStatic)391                {392                    results.Add(new PSInferredProperty("value__", new PSTypeName(typeof(int))));393                }394 395                baseMembersType = new PSTypeName(typeof(Enum));396            }397            else398            {399                baseMembersType = new PSTypeName(typeof(object));400            }401 402            results.AddRange(GetMembersByInferredType(baseMembersType, isStatic, filterToCall));403        }404 405        internal void AddMembersByInferredTypeCimType(PSTypeName typename, List<object> results, Func<object, bool> filterToCall)406        {407            if (ParseCimCommandsTypeName(typename, out var cimNamespace, out var className))408            {409                var powerShellExecutionHelper = Helper;410                powerShellExecutionHelper.AddCommandWithPreferenceSetting("CimCmdlets\\Get-CimClass")411                                         .AddParameter("Namespace", cimNamespace)412                                         .AddParameter("Class", className);413 414                var classes = powerShellExecutionHelper.ExecuteCurrentPowerShell(out _);415                var cimClasses = new List<CimClass>();416                foreach (var c in classes)417                {418                    if (PSObject.Base(c) is CimClass cc)419                    {420                        cimClasses.Add(cc);421                    }422                }423 424                foreach (var cimClass in cimClasses)425                {426                    if (filterToCall == null)427                    {428                        results.AddRange(cimClass.CimClassProperties);429                    }430                    else431                    {432                        foreach (var prop in cimClass.CimClassProperties)433                        {434                            if (filterToCall(prop))435                            {436                                results.Add(prop);437                            }438                        }439                    }440                }441            }442        }443 444        internal IEnumerable<PSTypeName> InferType(Ast ast, TypeInferenceVisitor visitor)445        {446            var res = ast.Accept(visitor);447            Diagnostics.Assert(res != null, "Fix visit methods to not return null");448            return (IEnumerable<PSTypeName>)res;449        }450 451        private static bool TryGetRepresentativeTypeNameFromValue(object value, out PSTypeName type)452        {453            type = null;454            if (value != null)455            {456                if (value is IList list457                    && list.Count > 0)458                {459                    value = list[0];460                }461 462                value = PSObject.Base(value);463                if (value != null)464                {465                    var typeObject = value.GetType();466                    467                    if (typeObject.FullName.Equals("System.Management.Automation.PSObject", StringComparison.Ordinal))468                    {469                        var psobjectPropertyList = new List<PSMemberNameAndType>();470                        foreach (var property in ((PSObject)value).Properties)471                        {472                            if (property.IsHidden)473                            {474                                continue;475                            }476 477                            var propertyTypeName = new PSTypeName(property.TypeNameOfValue);478                            psobjectPropertyList.Add(new PSMemberNameAndType(property.Name, propertyTypeName, property.Value));479                        }480 481                        type = PSSyntheticTypeName.Create(typeObject, psobjectPropertyList);482                    }483                    else484                    {485                        type = new PSTypeName(typeObject);486                    }487                    488                    return true;489                }490            }491 492            return false;493        }494 495        internal static bool ParseCimCommandsTypeName(PSTypeName typename, out string cimNamespace, out string className)496        {497            cimNamespace = null;498            className = null;499            if (typename == null)500            {501                return false;502            }503 504            if (typename.Type != null)505            {506                return false;507            }508 509            var match = Regex.Match(typename.Name, "(?<NetTypeName>.*)#(?<CimNamespace>.*)[/\\\\](?<CimClassName>.*)");510            if (!match.Success)511            {512                return false;513            }514 515            if (!match.Groups["NetTypeName"].Value.EqualsOrdinalIgnoreCase(typeof(CimInstance).FullName))516            {517                return false;518            }519 520            cimNamespace = match.Groups["CimNamespace"].Value;521            className = match.Groups["CimClassName"].Value;522            return true;523        }524 525        private static bool IsMemberHidden(object member)526        {527            switch (member)528            {529                case PSMemberInfo psMemberInfo:530                    return psMemberInfo.IsHidden;531                case MemberInfo memberInfo:532                    return memberInfo.GetCustomAttributes(typeof(HiddenAttribute), false).Length != 0;533                case PropertyMemberAst propertyMember:534                    return propertyMember.IsHidden;535                case FunctionMemberAst functionMember:536                    return functionMember.IsHidden;537            }538 539            return false;540        }541 542        private static bool IsConstructor(object member)543        {544            var psMethod = member as PSMethod;545            var methodCacheEntry = psMethod?.adapterData as DotNetAdapter.MethodCacheEntry;546            return methodCacheEntry != null && methodCacheEntry.methodInformationStructures[0].method.IsConstructor;547        }548    }549 550    internal class TypeInferenceVisitor : ICustomAstVisitor2551    {552        private readonly TypeInferenceContext _context;553 554        private static readonly PSTypeName StringPSTypeName = new PSTypeName(typeof(string));555 556        public TypeInferenceVisitor(TypeInferenceContext context)557        {558            _context = context;559        }560 561        private IEnumerable<PSTypeName> InferTypes(Ast ast)562        {563            return _context.InferType(ast, this);564        }565 566        object ICustomAstVisitor.VisitTypeExpression(TypeExpressionAst typeExpressionAst)567        {568            return new[] { new PSTypeName(typeExpressionAst.StaticType) };569        }570 571        object ICustomAstVisitor.VisitMemberExpression(MemberExpressionAst memberExpressionAst)572        {573            return InferTypesFrom(memberExpressionAst);574        }575 576        object ICustomAstVisitor.VisitInvokeMemberExpression(InvokeMemberExpressionAst invokeMemberExpressionAst)577        {578            return InferTypesFrom(invokeMemberExpressionAst);579        }580 581        object ICustomAstVisitor.VisitArrayExpression(ArrayExpressionAst arrayExpressionAst)582        {583            if (arrayExpressionAst.SubExpression.Statements.Count == 0)584            {585                return new[] { new PSTypeName(typeof(object[])) };586            }587 588            return new[] { GetArrayType(InferTypes(arrayExpressionAst.SubExpression)) };589        }590 591        object ICustomAstVisitor.VisitArrayLiteral(ArrayLiteralAst arrayLiteralAst)592        {593            var inferredElementTypes = new List<PSTypeName>();594            foreach (ExpressionAst expression in arrayLiteralAst.Elements)595            {596                inferredElementTypes.AddRange(InferTypes(expression));597            }598 599            return new[] { GetArrayType(inferredElementTypes) };600        }601 602        object ICustomAstVisitor.VisitHashtable(HashtableAst hashtableAst)603        {604            if (hashtableAst.KeyValuePairs.Count > 0)605            {606                var properties = new List<PSMemberNameAndType>();607                void AddInferredTypes(Ast ast, string keyName)608                {609                    bool foundAnyTypes = false;610                    foreach (PSTypeName item in InferTypes(ast))611                    {612                        foundAnyTypes = true;613                        properties.Add(new PSMemberNameAndType(keyName, item));614                    }615 616                    if (!foundAnyTypes)617                    {618                        properties.Add(new PSMemberNameAndType(keyName, new PSTypeName("System.Object")));619                    }620                }621 622                foreach (var kv in hashtableAst.KeyValuePairs)623                {624                    string name = null;625                    if (kv.Item1 is StringConstantExpressionAst stringConstantExpressionAst)626                    {627                        name = stringConstantExpressionAst.Value;628                    }629                    else if (kv.Item1 is ConstantExpressionAst constantExpressionAst)630                    {631                        name = constantExpressionAst.Value.ToString();632                    }633                    else if (SafeExprEvaluator.TrySafeEval(kv.Item1, _context.ExecutionContext, out object nameValue))634                    {635                        name = nameValue.ToString();636                    }637 638                    if (name is not null)639                    {640                        if (kv.Item2 is PipelineAst pipelineAst && pipelineAst.GetPureExpression() is ExpressionAst expression)641                        {642                            object value;643                            if (expression is ConstantExpressionAst constant)644                            {645                                value = constant.Value;646                            }647                            else648                            {649                                _ = SafeExprEvaluator.TrySafeEval(expression, _context.ExecutionContext, out value);650                            }651 652                            if (value is null)653                            {654                                AddInferredTypes(expression, name);655                                continue;656                            }657 658                            PSTypeName valueType = new(value.GetType());659                            properties.Add(new PSMemberNameAndType(name, valueType, value));660                        }661                        else662                        {663                            AddInferredTypes(kv.Item2, name);664                        }665                    }666                }667 668                return new[] { PSSyntheticTypeName.Create(typeof(Hashtable), properties) };669            }670 671            return new[] { new PSTypeName(typeof(Hashtable)) };672        }673 674        object ICustomAstVisitor.VisitScriptBlockExpression(ScriptBlockExpressionAst scriptBlockExpressionAst)675        {676            return new[] { new PSTypeName(typeof(ScriptBlock)) };677        }678 679        object ICustomAstVisitor.VisitParenExpression(ParenExpressionAst parenExpressionAst)680        {681            return parenExpressionAst.Pipeline.Accept(this);682        }683 684        object ICustomAstVisitor.VisitExpandableStringExpression(ExpandableStringExpressionAst expandableStringExpressionAst)685        {686            return new[] { StringPSTypeName };687        }688 689        object ICustomAstVisitor.VisitIndexExpression(IndexExpressionAst indexExpressionAst)690        {691            return InferTypeFrom(indexExpressionAst);692        }693 694        object ICustomAstVisitor.VisitAttributedExpression(AttributedExpressionAst attributedExpressionAst)695        {696            return attributedExpressionAst.Child.Accept(this);697        }698 699        object ICustomAstVisitor.VisitBlockStatement(BlockStatementAst blockStatementAst)700        {701            return blockStatementAst.Body.Accept(this);702        }703 704        object ICustomAstVisitor.VisitUsingExpression(UsingExpressionAst usingExpressionAst)705        {706            return usingExpressionAst.SubExpression.Accept(this);707        }708 709        object ICustomAstVisitor.VisitVariableExpression(VariableExpressionAst ast)710        {711            var inferredTypes = new List<PSTypeName>();712            InferTypeFrom(ast, inferredTypes);713            return inferredTypes;714        }715 716        object ICustomAstVisitor.VisitMergingRedirection(MergingRedirectionAst mergingRedirectionAst)717        {718            return TypeInferenceContext.EmptyPSTypeNameArray;719        }720 721        object ICustomAstVisitor.VisitBinaryExpression(BinaryExpressionAst binaryExpressionAst)722        {723            switch (binaryExpressionAst.Operator)724            {725                case TokenKind.And:726                case TokenKind.Ccontains:727                case TokenKind.Cin:728                case TokenKind.Cnotcontains:729                case TokenKind.Cnotin:730                case TokenKind.Icontains:731                case TokenKind.Iin:732                case TokenKind.Inotcontains:733                case TokenKind.Inotin:734                case TokenKind.Is:735                case TokenKind.IsNot:736                case TokenKind.Or:737                case TokenKind.Xor:738                    // Always returns a bool739                    return BinaryExpressionAst.BoolTypeNameArray;740 741                case TokenKind.As:742                    // TODO: Handle other kinds of expressions on the right side.743                    if (binaryExpressionAst.Right is TypeExpressionAst typeExpression)744                    {745                        var type = typeExpression.TypeName.GetReflectionType();746                        var psTypeName = type != null ? new PSTypeName(type) : new PSTypeName(typeExpression.TypeName.FullName);747                        return new[] { psTypeName };748                    }749                    break;750 751                case TokenKind.Ceq:752                case TokenKind.Cge:753                case TokenKind.Cgt:754                case TokenKind.Cle:755                case TokenKind.Clike:756                case TokenKind.Clt:757                case TokenKind.Cmatch:758                case TokenKind.Cne:759                case TokenKind.Cnotlike:760                case TokenKind.Cnotmatch:761                case TokenKind.Ieq:762                case TokenKind.Ige:763                case TokenKind.Igt:764                case TokenKind.Ile:765                case TokenKind.Ilike:766                case TokenKind.Ilt:767                case TokenKind.Imatch:768                case TokenKind.Ine:769                case TokenKind.Inotlike:770                case TokenKind.Inotmatch:771                    // Returns a bool or filtered output from the left hand side if it's enumerable772                    var comparisonOutput = new List<PSTypeName>() { new(typeof(bool)) };773                    comparisonOutput.AddRange(InferTypes(binaryExpressionAst.Left));774                    return comparisonOutput;775 776                case TokenKind.Creplace:777                case TokenKind.Format:778                case TokenKind.Ireplace:779                case TokenKind.Join:780                    // Always returns a string781                    return BinaryExpressionAst.StringTypeNameArray;782 783                case TokenKind.Csplit:784                case TokenKind.Isplit:785                    // Always returns a string array786                    return BinaryExpressionAst.StringArrayTypeNameArray;787 788                case TokenKind.QuestionQuestion:789                    // Can return left or right hand side790                    var nullCoalescingOutput = InferTypes(binaryExpressionAst.Left).ToList();791                    nullCoalescingOutput.AddRange(InferTypes(binaryExpressionAst.Right));792                    return nullCoalescingOutput.Distinct();793 794                default:795                    break;796            }797 798            List<PSTypeName> lhsTypes = InferTypes(binaryExpressionAst.Left).ToList();799            if (lhsTypes.Count == 0)800            {801                return lhsTypes;802            }803 804            string methodName;805            switch (binaryExpressionAst.Operator)806            {807                case TokenKind.Divide:808                    methodName = "op_Division";809                    break;810 811                case TokenKind.Minus:812                    methodName = "op_Subtraction";813                    break;814 815                case TokenKind.Multiply:816                    methodName = "op_Multiply";817                    break;818 819                case TokenKind.Plus:820                    methodName = "op_Addition";821                    break;822 823                case TokenKind.Rem:824                    methodName = "op_Modulus";825                    break;826 827                case TokenKind.Shl:828                    methodName = "op_LeftShift";829                    break;830 831                case TokenKind.Shr:832                    methodName = "op_RightShift";833                    break;834 835                default:836                    return lhsTypes;837            }838 839            List<PSTypeName> rhsTypes = InferTypes(binaryExpressionAst.Right).ToList();840            HashSet<string> addedReturnTypes = new HashSet<string>();841            List<PSTypeName> result = new List<PSTypeName>();842            foreach (PSTypeName lType in lhsTypes)843            {844                if (lType.Type is null)845                {846                    continue;847                }848 849                foreach (MethodInfo method in lType.Type.GetMethods(BindingFlags.Public | BindingFlags.Static))850                {851                    if (!method.Name.Equals(methodName, StringComparison.Ordinal))852                    {853                        continue;854                    }855 856                    if (rhsTypes.Count == 0)857                    {858                        if (addedReturnTypes.Add(method.ReturnType.FullName))859                        {860                            result.Add(new PSTypeName(method.ReturnType));861                        }862 863                        continue;864                    }865 866                    ParameterInfo[] methodParams = method.GetParameters();867                    if (methodParams.Length != 2)868                    {869                        continue;870                    }871 872                    foreach (PSTypeName rType in rhsTypes)873                    {874                        if (rType.Type is not null && rType.Type.IsAssignableTo(methodParams[1].ParameterType))875                        {876                            if (addedReturnTypes.Add(method.ReturnType.FullName))877                            {878                                result.Add(new PSTypeName(method.ReturnType));879                            }880 881                            break;882                        }883                    }884                }885            }886 887            if (result.Count == 0)888            {889                result.AddRange(lhsTypes);890            }891 892            return result;893        }894 895        object ICustomAstVisitor.VisitUnaryExpression(UnaryExpressionAst unaryExpressionAst)896        {897            var tokenKind = unaryExpressionAst.TokenKind;898            return (tokenKind == TokenKind.Not || tokenKind == TokenKind.Exclaim)899                   ? BinaryExpressionAst.BoolTypeNameArray900                   : unaryExpressionAst.Child.Accept(this);901        }902 903        object ICustomAstVisitor.VisitConvertExpression(ConvertExpressionAst convertExpressionAst)904        {905            // The reflection type of PSCustomObject is PSObject, so this covers both the906            // [PSObject] @{ Key = "Value" } and the [PSCustomObject] @{ Key = "Value" } case.907            var type = convertExpressionAst.Type.TypeName.GetReflectionType();908 909            if (type is null && convertExpressionAst.Type.TypeName is TypeName unavailableType && unavailableType._typeDefinitionAst is not null)910            {911                return new[] { new PSTypeName(unavailableType._typeDefinitionAst) };912            }913 914            if (type == typeof(PSObject) && convertExpressionAst.Child is HashtableAst hashtableAst)915            {916                if (InferTypes(hashtableAst).FirstOrDefault() is PSSyntheticTypeName syntheticTypeName)917                {918                    return new[] { PSSyntheticTypeName.Create(type, syntheticTypeName.Members) };919                }920            }921 922            var psTypeName = type != null ? new PSTypeName(type) : new PSTypeName(convertExpressionAst.Type.TypeName.FullName);923            return new[] { psTypeName };924        }925 926        object ICustomAstVisitor.VisitConstantExpression(ConstantExpressionAst constantExpressionAst)927        {928            var value = constantExpressionAst.Value;929            return value != null ? new[] { new PSTypeName(value.GetType()) } : TypeInferenceContext.EmptyPSTypeNameArray;930        }931 932        object ICustomAstVisitor.VisitStringConstantExpression(StringConstantExpressionAst stringConstantExpressionAst)933        {934            return new[] { StringPSTypeName };935        }936 937        object ICustomAstVisitor.VisitSubExpression(SubExpressionAst subExpressionAst)938        {939            return subExpressionAst.SubExpression.Accept(this);940        }941 942        object ICustomAstVisitor.VisitErrorStatement(ErrorStatementAst errorStatementAst)943        {944            var inferredTypes = new List<PSTypeName>();945            if (errorStatementAst.Conditions is not null)946            {947                foreach (var ast in errorStatementAst.Conditions)948                {949                    inferredTypes.AddRange(InferTypes(ast));950                }951            }952 953            if (errorStatementAst.Bodies is not null)954            {955                foreach (var ast in errorStatementAst.Bodies)956                {957                    inferredTypes.AddRange(InferTypes(ast));958                }959            }960 961            if (errorStatementAst.NestedAst is not null)962            {963                foreach (var ast in errorStatementAst.NestedAst)964                {965                    inferredTypes.AddRange(InferTypes(ast));966                }967            }968 969            return inferredTypes;970        }971 972        object ICustomAstVisitor.VisitErrorExpression(ErrorExpressionAst errorExpressionAst)973        {974            var inferredTypes = new List<PSTypeName>();975            foreach (var ast in errorExpressionAst.NestedAst)976            {977                inferredTypes.AddRange(InferTypes(ast));978            }979 980            return inferredTypes;981        }982 983        object ICustomAstVisitor.VisitScriptBlock(ScriptBlockAst scriptBlockAst)984        {985            var res = new List<PSTypeName>(10);986            var beginBlock = scriptBlockAst.BeginBlock;987            var processBlock = scriptBlockAst.ProcessBlock;988            var endBlock = scriptBlockAst.EndBlock;989 990            // The following is used when we don't find OutputType, which is checked elsewhere.991            if (beginBlock != null)992            {993                res.AddRange(InferTypes(beginBlock));994            }995 996            if (processBlock != null)997            {998                res.AddRange(InferTypes(processBlock));999            }1000 1001            if (endBlock != null)1002            {1003                res.AddRange(InferTypes(endBlock));1004            }1005 1006            return res;1007        }1008 1009        object ICustomAstVisitor.VisitParamBlock(ParamBlockAst paramBlockAst)1010        {1011            return TypeInferenceContext.EmptyPSTypeNameArray;1012        }1013 1014        object ICustomAstVisitor.VisitNamedBlock(NamedBlockAst namedBlockAst)1015        {1016            var inferredTypes = new List<PSTypeName>();1017            for (int index = 0; index < namedBlockAst.Statements.Count; index++)1018            {1019                StatementAst ast = namedBlockAst.Statements[index];1020                if (ast is AssignmentStatementAst1021                    || (ast is PipelineAst pipe && pipe.PipelineElements.Count == 1 && pipe.PipelineElements[0] is CommandExpressionAst cmd1022                    && cmd.Redirections.Count == 0 && cmd.Expression is UnaryExpressionAst unary1023                    && unary.TokenKind is TokenKind.PostfixPlusPlus or TokenKind.PlusPlus or TokenKind.PostfixMinusMinus or TokenKind.MinusMinus))1024                {1025                    // Assignments don't output anything to the named block unless they are wrapped in parentheses.1026                    // When they are wrapped in parentheses, they are seen as PipelineAst.1027                    // Increment/decrement operators like $i++ also don't output anything unless there's a redirection, or they are wrapped in parentheses.1028                    continue;1029                }1030 1031                inferredTypes.AddRange(InferTypes(ast));1032            }1033 1034            return inferredTypes;1035        }1036 1037        object ICustomAstVisitor.VisitTypeConstraint(TypeConstraintAst typeConstraintAst)1038        {1039            return TypeInferenceContext.EmptyPSTypeNameArray;1040        }1041 1042        object ICustomAstVisitor.VisitAttribute(AttributeAst attributeAst)1043        {1044            return TypeInferenceContext.EmptyPSTypeNameArray;1045        }1046 1047        object ICustomAstVisitor.VisitNamedAttributeArgument(NamedAttributeArgumentAst namedAttributeArgumentAst)1048        {1049            return TypeInferenceContext.EmptyPSTypeNameArray;1050        }1051 1052        object ICustomAstVisitor.VisitParameter(ParameterAst parameterAst)1053        {1054            var res = new List<PSTypeName>();1055            var attributes = parameterAst.Attributes;1056            bool typeConstraintAdded = false;1057            foreach (var attrib in attributes)1058            {1059                switch (attrib)1060                {1061                    case TypeConstraintAst typeConstraint:1062                        if (!typeConstraintAdded)1063                        {1064                            res.Add(new PSTypeName(typeConstraint.TypeName));1065                            typeConstraintAdded = true;1066                        }1067 1068                        break;1069                    case AttributeAst attributeAst:1070                        PSTypeNameAttribute attribute = null;1071                        try1072                        {1073                            attribute = attributeAst.GetAttribute() as PSTypeNameAttribute;1074                        }1075                        catch (RuntimeException)1076                        {1077                        }1078 1079                        if (attribute != null)1080                        {1081                            res.Add(new PSTypeName(attribute.PSTypeName));1082                        }1083 1084                        break;1085                }1086            }1087 1088            return res;1089        }1090 1091        object ICustomAstVisitor.VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst)1092        {1093            return TypeInferenceContext.EmptyPSTypeNameArray;1094        }1095 1096        object ICustomAstVisitor.VisitStatementBlock(StatementBlockAst statementBlockAst)1097        {1098            var inferredTypes = new List<PSTypeName>();1099            foreach (StatementAst ast in statementBlockAst.Statements)1100            {1101                if (ast is AssignmentStatementAst1102                    || (ast is PipelineAst pipe && pipe.PipelineElements.Count == 1 && pipe.PipelineElements[0] is CommandExpressionAst cmd1103                    && cmd.Redirections.Count == 0 && cmd.Expression is UnaryExpressionAst unary1104                    && unary.TokenKind is TokenKind.PostfixPlusPlus or TokenKind.PlusPlus or TokenKind.PostfixMinusMinus or TokenKind.MinusMinus))1105                {1106                    // Assignments don't output anything to the statement block unless they are wrapped in parentheses.1107                    // When they are wrapped in parentheses, they are seen as PipelineAst.1108                    // Increment operators like $i++ also don't output anything unless there's a redirection, or they are wrapped in parentheses.1109                    continue;1110                }1111 1112                inferredTypes.AddRange(InferTypes(ast));1113            }1114 1115            return inferredTypes;1116        }1117 1118        object ICustomAstVisitor.VisitIfStatement(IfStatementAst ifStmtAst)1119        {1120            var res = new List<PSTypeName>();1121 1122            foreach (var clause in ifStmtAst.Clauses)1123            {1124                res.AddRange(InferTypes(clause.Item2));1125            }1126 1127            var elseClause = ifStmtAst.ElseClause;1128            if (elseClause != null)1129            {1130                res.AddRange(InferTypes(elseClause));1131            }1132 1133            return res;1134        }1135 1136        object ICustomAstVisitor.VisitTrap(TrapStatementAst trapStatementAst)1137        {1138            return trapStatementAst.Body.Accept(this);1139        }1140 1141        object ICustomAstVisitor.VisitSwitchStatement(SwitchStatementAst switchStatementAst)1142        {1143            var res = new List<PSTypeName>(8);1144            var clauses = switchStatementAst.Clauses;1145            var defaultStatement = switchStatementAst.Default;1146 1147            foreach (var clause in clauses)1148            {1149                res.AddRange(InferTypes(clause.Item2));1150            }1151 1152            if (defaultStatement != null)1153            {1154                res.AddRange(InferTypes(defaultStatement));1155            }1156 1157            return res;1158        }1159 1160        object ICustomAstVisitor.VisitDataStatement(DataStatementAst dataStatementAst)1161        {1162            return dataStatementAst.Body.Accept(this);1163        }1164 1165        object ICustomAstVisitor.VisitForEachStatement(ForEachStatementAst forEachStatementAst)1166        {1167            return forEachStatementAst.Body.Accept(this);1168        }1169 1170        object ICustomAstVisitor.VisitDoWhileStatement(DoWhileStatementAst doWhileStatementAst)1171        {1172            return doWhileStatementAst.Body.Accept(this);1173        }1174 1175        object ICustomAstVisitor.VisitForStatement(ForStatementAst forStatementAst)1176        {1177            return forStatementAst.Body.Accept(this);1178        }1179 1180        object ICustomAstVisitor.VisitWhileStatement(WhileStatementAst whileStatementAst)1181        {1182            return whileStatementAst.Body.Accept(this);1183        }1184 1185        object ICustomAstVisitor.VisitCatchClause(CatchClauseAst catchClauseAst)1186        {1187            return catchClauseAst.Body.Accept(this);1188        }1189 1190        object ICustomAstVisitor.VisitTryStatement(TryStatementAst tryStatementAst)1191        {1192            var res = new List<PSTypeName>(5);1193            res.AddRange(InferTypes(tryStatementAst.Body));1194            foreach (var catchClauseAst in tryStatementAst.CatchClauses)1195            {1196                res.AddRange(InferTypes(catchClauseAst));1197            }1198 1199            if (tryStatementAst.Finally != null)1200            {

Showing the first 1,200 of 3339 lines. Download the file for the rest.