MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.Generic;5using System.Collections.ObjectModel;6using System.Diagnostics.CodeAnalysis;7using System.Globalization;8using System.Linq;9using System.Management.Automation.Internal;10using System.Reflection;11using System.Reflection.Emit;12using System.Threading;13 14using Microsoft.PowerShell;15 16namespace System.Management.Automation.Language17{18 internal static class TypeDefiner19 {20 internal const string DynamicClassAssemblyName = "PowerShell Class Assembly";21 internal const string DynamicClassAssemblyFullNamePrefix = "PowerShell Class Assembly,";22 23 private static int s_globalCounter = 0;24 25 private static readonly CustomAttributeBuilder s_hiddenCustomAttributeBuilder =26 new CustomAttributeBuilder(typeof(HiddenAttribute).GetConstructor(Type.EmptyTypes), Array.Empty<object>());27 28 private static readonly string s_sessionStateKeeperFieldName = "__sessionStateKeeper";29 internal static readonly string SessionStateFieldName = "__sessionState";30 31 private static readonly MethodInfo s_sessionStateKeeper_GetSessionState =32 typeof(SessionStateKeeper).GetMethod("GetSessionState", BindingFlags.Instance | BindingFlags.Public);33 34 private static bool TryConvertArg(object arg, Type type, out object result, Parser parser, IScriptExtent errorExtent)35 {36 // This code could be added to LanguagePrimitives.ConvertTo37 if (arg != null && arg.GetType() == type)38 {39 result = arg;40 return true;41 }42 43 if (!LanguagePrimitives.TryConvertTo(arg, type, out result))44 {45 parser.ReportError(errorExtent,46 nameof(ParserStrings.CannotConvertValue),47 ParserStrings.CannotConvertValue,48 ToStringCodeMethods.Type(type));49 return false;50 }51 52 return true;53 }54 55 private static CustomAttributeBuilder GetAttributeBuilder(Parser parser, AttributeAst attributeAst, AttributeTargets attributeTargets)56 {57 var attributeType = attributeAst.TypeName.GetReflectionAttributeType();58 Diagnostics.Assert(attributeType != null, "Semantic checks should have verified attribute type exists");59 60 Diagnostics.Assert(61 attributeType.GetCustomAttribute<AttributeUsageAttribute>(true) == null ||62 (attributeType.GetCustomAttribute<AttributeUsageAttribute>(true).ValidOn & attributeTargets) != 0, "Semantic checks should have verified attribute usage");63 64 var positionalArgs = new object[attributeAst.PositionalArguments.Count];65 var cvv = new ConstantValueVisitor { AttributeArgument = false };66 for (var i = 0; i < attributeAst.PositionalArguments.Count; i++)67 {68 var posArg = attributeAst.PositionalArguments[i];69 positionalArgs[i] = posArg.Accept(cvv);70 }71 72 var ctorInfos = attributeType.GetConstructors();73 var newConstructors = DotNetAdapter.GetMethodInformationArray(ctorInfos);74 75 string errorId = null;76 string errorMsg = null;77 bool expandParamsOnBest;78 bool callNonVirtually;79 var positionalArgCount = positionalArgs.Length;80 81 var bestMethod = Adapter.FindBestMethod(82 newConstructors,83 invocationConstraints: null,84 allowCastingToByRefLikeType: false,85 positionalArgs,86 ref errorId,87 ref errorMsg,88 out expandParamsOnBest,89 out callNonVirtually);90 91 if (bestMethod == null)92 {93 parser.ReportError(new ParseError(attributeAst.Extent, errorId,94 string.Format(CultureInfo.InvariantCulture, errorMsg, attributeType.Name, attributeAst.PositionalArguments.Count)));95 return null;96 }97 98 var constructorInfo = (ConstructorInfo)bestMethod.method;99 100 var parameterInfo = constructorInfo.GetParameters();101 var ctorArgs = new object[parameterInfo.Length];102 object arg;103 for (var argIndex = 0; argIndex < parameterInfo.Length; ++argIndex)104 {105 var resultType = parameterInfo[argIndex].ParameterType;106 107 // The extension method 'CustomAttributeExtensions.GetCustomAttributes(ParameterInfo, Type, Boolean)' has inconsistent108 // behavior on its return value in both FullCLR and CoreCLR. According to MSDN, if the attribute cannot be found, it109 // should return an empty collection. However, it returns null in some rare cases [when the parameter isn't backed by110 // actual metadata].111 // This inconsistent behavior affects OneCore powershell because we are using the extension method here when compiling112 // against CoreCLR. So we need to add a null check until this is fixed in CLR.113 var paramArrayAttrs = parameterInfo[argIndex].GetCustomAttributes(typeof(ParamArrayAttribute), true);114 if (paramArrayAttrs != null && paramArrayAttrs.Length > 0 && expandParamsOnBest)115 {116 var elementType = parameterInfo[argIndex].ParameterType.GetElementType();117 var paramsArray = Array.CreateInstance(elementType, positionalArgCount - argIndex);118 ctorArgs[argIndex] = paramsArray;119 120 for (var i = 0; i < paramsArray.Length; ++i, ++argIndex)121 {122 if (!TryConvertArg(positionalArgs[argIndex], elementType, out arg,123 parser, attributeAst.PositionalArguments[argIndex].Extent))124 {125 return null;126 }127 128 paramsArray.SetValue(arg, i);129 }130 131 break;132 }133 134 if (!TryConvertArg(positionalArgs[argIndex], resultType, out arg,135 parser, attributeAst.PositionalArguments[argIndex].Extent))136 {137 return null;138 }139 140 ctorArgs[argIndex] = arg;141 }142 143 if (attributeAst.NamedArguments.Count == 0)144 {145 return new CustomAttributeBuilder(constructorInfo, ctorArgs);146 }147 148 var propertyInfoList = new List<PropertyInfo>();149 var propertyArgs = new List<object>();150 var fieldInfoList = new List<FieldInfo>();151 var fieldArgs = new List<object>();152 foreach (var namedArg in attributeAst.NamedArguments)153 {154 var name = namedArg.ArgumentName;155 var members = attributeType.GetMember(name, MemberTypes.Field | MemberTypes.Property,156 BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy);157 Diagnostics.Assert(members.Length == 1 && (members[0] is PropertyInfo || members[0] is FieldInfo),158 "Semantic checks should have ensured names attribute argument exists");159 160 arg = namedArg.Argument.Accept(cvv);161 162 var propertyInfo = members[0] as PropertyInfo;163 if (propertyInfo != null)164 {165 Diagnostics.Assert(propertyInfo.GetSetMethod() != null, "Semantic checks ensures property is settable");166 167 if (!TryConvertArg(arg, propertyInfo.PropertyType, out arg, parser, namedArg.Argument.Extent))168 {169 return null;170 }171 172 propertyInfoList.Add(propertyInfo);173 propertyArgs.Add(arg);174 continue;175 }176 177 var fieldInfo = (FieldInfo)members[0];178 Diagnostics.Assert(!fieldInfo.IsInitOnly && !fieldInfo.IsLiteral, "Semantic checks ensures field is settable");179 180 if (!TryConvertArg(arg, fieldInfo.FieldType, out arg, parser, namedArg.Argument.Extent))181 {182 return null;183 }184 185 fieldInfoList.Add(fieldInfo);186 fieldArgs.Add(arg);187 }188 189 return new CustomAttributeBuilder(constructorInfo, ctorArgs,190 propertyInfoList.ToArray(), propertyArgs.ToArray(),191 fieldInfoList.ToArray(), fieldArgs.ToArray());192 }193 194 internal static void DefineCustomAttributes(TypeBuilder member, ReadOnlyCollection<AttributeAst> attributes, Parser parser, AttributeTargets attributeTargets)195 {196 if (attributes != null)197 {198 foreach (var attr in attributes)199 {200 var cabuilder = GetAttributeBuilder(parser, attr, attributeTargets);201 if (cabuilder != null)202 {203 member.SetCustomAttribute(cabuilder);204 }205 }206 }207 }208 209 internal static void DefineCustomAttributes(PropertyBuilder member, ReadOnlyCollection<AttributeAst> attributes, Parser parser, AttributeTargets attributeTargets)210 {211 if (attributes != null)212 {213 foreach (var attr in attributes)214 {215 var cabuilder = GetAttributeBuilder(parser, attr, attributeTargets);216 if (cabuilder != null)217 {218 member.SetCustomAttribute(cabuilder);219 }220 }221 }222 }223 224 internal static void DefineCustomAttributes(ConstructorBuilder member, ReadOnlyCollection<AttributeAst> attributes, Parser parser, AttributeTargets attributeTargets)225 {226 if (attributes != null)227 {228 foreach (var attr in attributes)229 {230 var cabuilder = GetAttributeBuilder(parser, attr, attributeTargets);231 if (cabuilder != null)232 {233 member.SetCustomAttribute(cabuilder);234 }235 }236 }237 }238 239 internal static void DefineCustomAttributes(MethodBuilder member, ReadOnlyCollection<AttributeAst> attributes, Parser parser, AttributeTargets attributeTargets)240 {241 if (attributes != null)242 {243 foreach (var attr in attributes)244 {245 var cabuilder = GetAttributeBuilder(parser, attr, attributeTargets);246 if (cabuilder != null)247 {248 member.SetCustomAttribute(cabuilder);249 }250 }251 }252 }253 254 internal static void DefineCustomAttributes(EnumBuilder member, ReadOnlyCollection<AttributeAst> attributes, Parser parser, AttributeTargets attributeTargets)255 {256 if (attributes != null)257 {258 foreach (var attr in attributes)259 {260 var cabuilder = GetAttributeBuilder(parser, attr, attributeTargets);261 if (cabuilder != null)262 {263 member.SetCustomAttribute(cabuilder);264 }265 }266 }267 }268 269 private sealed class DefineTypeHelper270 {271 private readonly Parser _parser;272 internal readonly TypeDefinitionAst _typeDefinitionAst;273 internal readonly TypeBuilder _typeBuilder;274 internal readonly FieldBuilder _sessionStateField;275 internal readonly FieldBuilder _sessionStateKeeperField;276 internal readonly ModuleBuilder _moduleBuilder;277 internal readonly TypeBuilder _staticHelpersTypeBuilder;278 private readonly Dictionary<string, PropertyMemberAst> _definedProperties;279 private readonly Dictionary<string, List<Tuple<FunctionMemberAst, Type[]>>> _definedMethods;280 private Dictionary<Tuple<string, Type>, PropertyInfo> _abstractProperties;281 internal readonly List<(string fieldName, IParameterMetadataProvider bodyAst, bool isStatic)> _fieldsToInitForMemberFunctions;282 private bool _baseClassHasDefaultCtor;283 284 /// <summary>285 /// If type has fatal errors we cannot construct .NET type from it.286 /// TypeBuilder.CreateTypeInfo() would throw exception.287 /// </summary>288 public bool HasFatalErrors { get; private set; }289 290 public DefineTypeHelper(Parser parser, ModuleBuilder module, TypeDefinitionAst typeDefinitionAst, string typeName)291 {292 _moduleBuilder = module;293 _parser = parser;294 _typeDefinitionAst = typeDefinitionAst;295 296 List<Type> interfaces;297 var baseClass = this.GetBaseTypes(parser, typeDefinitionAst, out interfaces);298 299 _typeBuilder = module.DefineType(typeName, Reflection.TypeAttributes.Class | Reflection.TypeAttributes.Public, baseClass, interfaces.ToArray());300 _staticHelpersTypeBuilder = module.DefineType(string.Create(CultureInfo.InvariantCulture, $"{typeName}_<staticHelpers>"), Reflection.TypeAttributes.Class);301 DefineCustomAttributes(_typeBuilder, typeDefinitionAst.Attributes, _parser, AttributeTargets.Class);302 _typeDefinitionAst.Type = _typeBuilder;303 304 _fieldsToInitForMemberFunctions = new List<(string, IParameterMetadataProvider, bool)>();305 _definedMethods = new Dictionary<string, List<Tuple<FunctionMemberAst, Type[]>>>(StringComparer.OrdinalIgnoreCase);306 _definedProperties = new Dictionary<string, PropertyMemberAst>(StringComparer.OrdinalIgnoreCase);307 308 _sessionStateField = _typeBuilder.DefineField(SessionStateFieldName, typeof(SessionStateInternal), FieldAttributes.Private);309 _sessionStateKeeperField = _staticHelpersTypeBuilder.DefineField(s_sessionStateKeeperFieldName, typeof(SessionStateKeeper), FieldAttributes.Assembly | FieldAttributes.Static);310 }311 312 /// <summary>313 /// Return base class type, never return null.314 /// </summary>315 /// <param name="parser"></param>316 /// <param name="typeDefinitionAst"></param>317 /// <param name="interfaces">Return declared interfaces.</param>318 /// <returns></returns>319 private Type GetBaseTypes(Parser parser, TypeDefinitionAst typeDefinitionAst, out List<Type> interfaces)320 {321 // Define base types and report errors.322 Type baseClass = null;323 interfaces = new List<Type>();324 325 // Default base class is System.Object and it has a default ctor.326 _baseClassHasDefaultCtor = true;327 if (typeDefinitionAst.BaseTypes.Count > 0)328 {329 // base class330 var baseTypeAsts = typeDefinitionAst.BaseTypes;331 var firstBaseTypeAst = baseTypeAsts[0];332 333 if (firstBaseTypeAst.TypeName.IsArray)334 {335 parser.ReportError(firstBaseTypeAst.Extent,336 nameof(ParserStrings.SubtypeArray),337 ParserStrings.SubtypeArray,338 firstBaseTypeAst.TypeName.FullName);339 // fall to the default base type340 }341 else342 {343 baseClass = firstBaseTypeAst.TypeName.GetReflectionType();344 if (baseClass == null)345 {346 parser.ReportError(firstBaseTypeAst.Extent,347 nameof(ParserStrings.TypeNotFound),348 ParserStrings.TypeNotFound,349 firstBaseTypeAst.TypeName.FullName);350 // fall to the default base type351 }352 else353 {354 if (baseClass.IsSealed)355 {356 parser.ReportError(firstBaseTypeAst.Extent,357 nameof(ParserStrings.SealedBaseClass),358 ParserStrings.SealedBaseClass,359 baseClass.Name);360 // ignore base type if it's sealed.361 baseClass = null;362 }363 else if (baseClass.IsGenericType && !baseClass.IsConstructedGenericType)364 {365 parser.ReportError(firstBaseTypeAst.Extent,366 nameof(ParserStrings.SubtypeUnclosedGeneric),367 ParserStrings.SubtypeUnclosedGeneric,368 baseClass.Name);369 // ignore base type, we cannot inherit from unclosed generic.370 baseClass = null;371 }372 else if (baseClass.IsInterface)373 {374 // First Ast can represent interface as well as BaseClass.375 interfaces.Add(baseClass);376 baseClass = null;377 }378 }379 }380 381 if (baseClass != null)382 {383 // All PS classes are TypeName instances.384 // For PS classes we cannot use reflection API, because type is not created yet.385 var baseTypeName = firstBaseTypeAst.TypeName as TypeName;386 if (baseTypeName != null)387 {388 _baseClassHasDefaultCtor = baseTypeName.HasDefaultCtor();389 }390 else391 {392 _baseClassHasDefaultCtor = baseClass.HasDefaultCtor();393 }394 }395 396 for (int i = 0; i < baseTypeAsts.Count; i++)397 {398 if (baseTypeAsts[i].TypeName.IsArray)399 {400 parser.ReportError(baseTypeAsts[i].Extent,401 nameof(ParserStrings.SubtypeArray),402 ParserStrings.SubtypeArray,403 baseTypeAsts[i].TypeName.FullName);404 this.HasFatalErrors = true;405 }406 }407 408 for (int i = 1; i < baseTypeAsts.Count; i++)409 {410 if (baseTypeAsts[i].TypeName.IsArray)411 {412 parser.ReportError(baseTypeAsts[i].Extent,413 nameof(ParserStrings.SubtypeArray),414 ParserStrings.SubtypeArray,415 baseTypeAsts[i].TypeName.FullName);416 }417 else418 {419 Type interfaceType = baseTypeAsts[i].TypeName.GetReflectionType();420 if (interfaceType == null)421 {422 parser.ReportError(baseTypeAsts[i].Extent,423 nameof(ParserStrings.TypeNotFound),424 ParserStrings.TypeNotFound,425 baseTypeAsts[i].TypeName.FullName);426 }427 else428 {429 if (interfaceType.IsInterface)430 {431 interfaces.Add(interfaceType);432 }433 else434 {435 parser.ReportError(baseTypeAsts[i].Extent,436 nameof(ParserStrings.InterfaceNameExpected),437 ParserStrings.InterfaceNameExpected,438 interfaceType.Name);439 }440 }441 }442 }443 }444 445 return baseClass ?? typeof(object);446 }447 448 private bool ShouldImplementProperty(string name, Type type, [NotNullWhen(true)] out PropertyInfo interfaceProperty)449 {450 if (_abstractProperties == null)451 {452 _abstractProperties = new Dictionary<Tuple<string, Type>, PropertyInfo>();453 var allInterfaces = new HashSet<Type>();454 455 // TypeBuilder.GetInterfaces() returns only the interfaces that was explicitly passed to its constructor.456 // During compilation the interface hierarchy is flattened, so we only need to resolve one level of ancestral interfaces.457 foreach (var interfaceType in _typeBuilder.GetInterfaces())458 {459 foreach (var parentInterface in interfaceType.GetInterfaces())460 {461 allInterfaces.Add(parentInterface);462 }463 464 allInterfaces.Add(interfaceType);465 }466 467 foreach (var interfaceType in allInterfaces)468 {469 foreach (var property in interfaceType.GetProperties())470 {471 _abstractProperties.Add(Tuple.Create(property.Name, property.PropertyType), property);472 }473 }474 475 if (_typeBuilder.BaseType.IsAbstract)476 {477 foreach (var property in _typeBuilder.BaseType.GetProperties())478 {479 if (property.GetAccessors().Any(m => m.IsAbstract))480 {481 _abstractProperties.Add(Tuple.Create(property.Name, property.PropertyType), property);482 }483 }484 }485 }486 487 return _abstractProperties.TryGetValue(Tuple.Create(name, type), out interfaceProperty);488 }489 490 public void DefineMembers()491 {492 // If user didn't provide any instance ctors or static ctor we will generate default ctor or static ctor respectively.493 // We can avoid explicit default ctor and static ctor, if we don't have any properties to initialize.494 bool needStaticCtor = false;495 bool needDefaultCtor = false;496 bool hasAnyMethods = false;497 List<FunctionMemberAst> staticCtors = new List<FunctionMemberAst>();498 List<FunctionMemberAst> instanceCtors = new List<FunctionMemberAst>();499 500 foreach (var member in _typeDefinitionAst.Members)501 {502 var propertyMemberAst = member as PropertyMemberAst;503 if (propertyMemberAst != null)504 {505 DefineProperty(propertyMemberAst);506 if (propertyMemberAst.InitialValue != null)507 {508 if (propertyMemberAst.IsStatic)509 {510 needStaticCtor = true;511 }512 else513 {514 needDefaultCtor = true;515 }516 }517 }518 else519 {520 FunctionMemberAst method = member as FunctionMemberAst;521 Diagnostics.Assert(method != null, StringUtil.Format("Unexpected subtype of MemberAst '{0}'. Expect `{1}`",522 member.GetType().Name, typeof(FunctionMemberAst).GetType().Name));523 if (method.IsConstructor)524 {525 if (method.IsStatic)526 {527 staticCtors.Add(method);528 }529 else530 {531 instanceCtors.Add(method);532 }533 }534 535 hasAnyMethods = true;536 537 DefineMethod(method);538 }539 }540 541 // inside ctor we put logic to capture session state from execution context,542 // we cannot delegate default ctor creation to _typeBuilder, if we have any methods.543 // If there are only static methods, we still want to capture context to allow static method calls on instances in the right context.544 if (hasAnyMethods)545 {546 needDefaultCtor = true;547 }548 549 if (needStaticCtor)550 {551 foreach (var ctor in staticCtors)552 {553 var parameters = ((IParameterMetadataProvider)ctor.Body).Parameters;554 // We report error for static ctors with parameters, even with default values.555 // We don't take them into account.556 if (parameters == null || parameters.Count == 0)557 {558 needStaticCtor = false;559 }560 }561 }562 563 if (needDefaultCtor)564 {565 needDefaultCtor = instanceCtors.Count == 0;566 }567 568 //// Now we can decide to create explicit default ctors or report error.569 570 if (needStaticCtor)571 {572 var staticCtorAst = new CompilerGeneratedMemberFunctionAst(PositionUtilities.EmptyExtent, _typeDefinitionAst, SpecialMemberFunctionType.StaticConstructor);573 DefineConstructor(staticCtorAst, null, true, Reflection.MethodAttributes.Private | Reflection.MethodAttributes.Static, Type.EmptyTypes);574 }575 576 if (_baseClassHasDefaultCtor)577 {578 if (needDefaultCtor)579 {580 var defaultCtorAst = new CompilerGeneratedMemberFunctionAst(PositionUtilities.EmptyExtent, _typeDefinitionAst, SpecialMemberFunctionType.DefaultConstructor);581 DefineConstructor(defaultCtorAst, null, true, Reflection.MethodAttributes.Public, Type.EmptyTypes);582 }583 }584 else585 {586 if (instanceCtors.Count == 0)587 {588 _parser.ReportError(_typeDefinitionAst.Extent,589 nameof(ParserStrings.BaseClassNoDefaultCtor),590 ParserStrings.BaseClassNoDefaultCtor,591 _typeBuilder.BaseType.Name);592 this.HasFatalErrors = true;593 }594 }595 }596 597 private void DefineProperty(PropertyMemberAst propertyMemberAst)598 {599 if (_definedProperties.ContainsKey(propertyMemberAst.Name))600 {601 _parser.ReportError(propertyMemberAst.Extent,602 nameof(ParserStrings.MemberAlreadyDefined),603 ParserStrings.MemberAlreadyDefined,604 propertyMemberAst.Name);605 return;606 }607 608 _definedProperties.Add(propertyMemberAst.Name, propertyMemberAst);609 610 Type type;611 if (propertyMemberAst.PropertyType == null)612 {613 type = typeof(object);614 }615 else616 {617 type = propertyMemberAst.PropertyType.TypeName.GetReflectionType();618 Diagnostics.Assert(type != null, "Semantic checks should have ensure type can't be null");619 }620 621 PropertyBuilder property = this.EmitPropertyIl(propertyMemberAst, type);622 // Define custom attributes on the property, not on the backingField623 DefineCustomAttributes(property, propertyMemberAst.Attributes, _parser, AttributeTargets.Field | AttributeTargets.Property);624 }625 626 private PropertyBuilder EmitPropertyIl(PropertyMemberAst propertyMemberAst, Type type)627 {628 // backing field is always private.629 var backingFieldAttributes = FieldAttributes.Private;630 // The property set and property get methods require a special set of attributes.631 var getSetAttributes = Reflection.MethodAttributes.SpecialName | Reflection.MethodAttributes.HideBySig;632 getSetAttributes |= propertyMemberAst.IsPublic ? Reflection.MethodAttributes.Public : Reflection.MethodAttributes.Private;633 MethodInfo implementingGetter = null;634 MethodInfo implementingSetter = null;635 if (ShouldImplementProperty(propertyMemberAst.Name, type, out PropertyInfo interfaceProperty))636 {637 if (propertyMemberAst.IsStatic)638 {639 implementingGetter = interfaceProperty.GetGetMethod();640 implementingSetter = interfaceProperty.GetSetMethod();641 }642 else643 {644 getSetAttributes |= Reflection.MethodAttributes.Virtual;645 }646 }647 648 if (propertyMemberAst.IsStatic)649 {650 backingFieldAttributes |= FieldAttributes.Static;651 getSetAttributes |= Reflection.MethodAttributes.Static;652 }653 // C# naming convention for backing fields.654 string backingFieldName = string.Create(CultureInfo.InvariantCulture, $"<{propertyMemberAst.Name}>k__BackingField");655 var backingField = _typeBuilder.DefineField(backingFieldName, type, backingFieldAttributes);656 657 bool hasValidateAttributes = false;658 if (propertyMemberAst.Attributes != null)659 {660 for (int i = 0; i < propertyMemberAst.Attributes.Count; i++)661 {662 Type attributeType = propertyMemberAst.Attributes[i].TypeName.GetReflectionAttributeType();663 if (attributeType != null && attributeType.IsSubclassOf(typeof(ValidateArgumentsAttribute)))664 {665 hasValidateAttributes = true;666 break;667 }668 }669 }670 671 // The last argument of DefineProperty is null, because the property has no parameters.672 PropertyBuilder property = _typeBuilder.DefineProperty(propertyMemberAst.Name, Reflection.PropertyAttributes.None, type, null);673 674 // Define the "get" accessor method.675 MethodBuilder getMethod = _typeBuilder.DefineMethod(string.Concat("get_", propertyMemberAst.Name), getSetAttributes, type, Type.EmptyTypes);676 ILGenerator getIlGen = getMethod.GetILGenerator();677 if (propertyMemberAst.IsStatic)678 {679 // static680 getIlGen.Emit(OpCodes.Ldsfld, backingField);681 getIlGen.Emit(OpCodes.Ret);682 }683 else684 {685 // instance686 getIlGen.Emit(OpCodes.Ldarg_0);687 getIlGen.Emit(OpCodes.Ldfld, backingField);688 getIlGen.Emit(OpCodes.Ret);689 }690 691 if (implementingGetter != null)692 {693 _typeBuilder.DefineMethodOverride(getMethod, implementingGetter);694 }695 696 // Define the "set" accessor method.697 MethodBuilder setMethod = _typeBuilder.DefineMethod(string.Concat("set_", propertyMemberAst.Name), getSetAttributes, null, new Type[] { type });698 ILGenerator setIlGen = setMethod.GetILGenerator();699 700 if (hasValidateAttributes)701 {702 Type typeToLoad = _typeBuilder;703 setIlGen.Emit(OpCodes.Ldtoken, typeToLoad);704 setIlGen.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle")); // load current Type on stack705 setIlGen.Emit(OpCodes.Ldstr, propertyMemberAst.Name); // load name of Property706 setIlGen.Emit(propertyMemberAst.IsStatic ? OpCodes.Ldarg_0 : OpCodes.Ldarg_1); // load set value707 if (type.IsValueType)708 {709 setIlGen.Emit(OpCodes.Box, type);710 }711 712 setIlGen.Emit(OpCodes.Call, CachedReflectionInfo.ClassOps_ValidateSetProperty);713 }714 715 if (propertyMemberAst.IsStatic)716 {717 setIlGen.Emit(OpCodes.Ldarg_0);718 setIlGen.Emit(OpCodes.Stsfld, backingField);719 }720 else721 {722 setIlGen.Emit(OpCodes.Ldarg_0);723 setIlGen.Emit(OpCodes.Ldarg_1);724 setIlGen.Emit(OpCodes.Stfld, backingField);725 }726 727 setIlGen.Emit(OpCodes.Ret);728 729 if (implementingSetter != null)730 {731 _typeBuilder.DefineMethodOverride(setMethod, implementingSetter);732 }733 734 // Map the two methods created above to our PropertyBuilder to735 // their corresponding behaviors, "get" and "set" respectively.736 property.SetGetMethod(getMethod);737 property.SetSetMethod(setMethod);738 739 if (propertyMemberAst.IsHidden)740 {741 property.SetCustomAttribute(s_hiddenCustomAttributeBuilder);742 }743 744 return property;745 }746 747 private bool CheckForDuplicateOverload(FunctionMemberAst functionMemberAst, Type[] newParameters)748 {749 List<Tuple<FunctionMemberAst, Type[]>> overloads;750 if (!_definedMethods.TryGetValue(functionMemberAst.Name, out overloads))751 {752 overloads = new List<Tuple<FunctionMemberAst, Type[]>>();753 _definedMethods.Add(functionMemberAst.Name, overloads);754 }755 else756 {757 foreach (var overload in overloads)758 {759 var overloadParameters = overload.Item2;760 761 // This test won't be correct when defaults are supported762 if (newParameters.Length != overloadParameters.Length)763 {764 continue;765 }766 767 var sameSignature = true;768 for (int i = 0; i < newParameters.Length; i++)769 {770 if (newParameters[i] != overloadParameters[i])771 {772 sameSignature = false;773 break;774 }775 }776 777 if (sameSignature)778 {779 // If both are both static/instance, it's an error.780 // Otherwise, signatures can match only for the constructor.781 if (overload.Item1.IsStatic == functionMemberAst.IsStatic ||782 !functionMemberAst.IsConstructor)783 {784 _parser.ReportError(functionMemberAst.NameExtent ?? functionMemberAst.Extent,785 nameof(ParserStrings.MemberAlreadyDefined),786 ParserStrings.MemberAlreadyDefined,787 functionMemberAst.Name);788 return true;789 }790 }791 }792 }793 794 overloads.Add(Tuple.Create(functionMemberAst, newParameters));795 return false;796 }797 798 private Type[] GetParameterTypes(FunctionMemberAst functionMemberAst)799 {800 var parameters = ((IParameterMetadataProvider)functionMemberAst).Parameters;801 if (parameters == null)802 {803 return Type.EmptyTypes;804 }805 806 bool anyErrors = false;807 var result = new Type[parameters.Count];808 for (var i = 0; i < parameters.Count; i++)809 {810 var typeConstraint = parameters[i].Attributes.OfType<TypeConstraintAst>().FirstOrDefault();811 var paramType = (typeConstraint != null)812 ? typeConstraint.TypeName.GetReflectionType()813 : typeof(object);814 if (paramType == null)815 {816 _parser.ReportError(typeConstraint.Extent,817 nameof(ParserStrings.TypeNotFound),818 ParserStrings.TypeNotFound,819 typeConstraint.TypeName.FullName);820 anyErrors = true;821 }822 else if (paramType == typeof(void) || paramType.IsGenericTypeDefinition)823 {824 _parser.ReportError(typeConstraint.Extent,825 nameof(ParserStrings.TypeNotAllowedForParameter),826 ParserStrings.TypeNotAllowedForParameter,827 typeConstraint.TypeName.FullName);828 anyErrors = true;829 }830 831 result[i] = paramType;832 }833 834 return anyErrors ? null : result;835 }836 837 private bool MethodExistsOnBaseClassAndFinal(string methodName, Type[] parameterTypes)838 {839 Type baseType = _typeBuilder.BaseType;840 841 // If baseType is PS class, then method will be virtual, once we define it.842 if (baseType is TypeBuilder)843 {844 return false;845 }846 847 var mi = baseType.GetMethod(methodName, parameterTypes);848 return mi != null && mi.IsFinal;849 }850 851 private void DefineMethod(FunctionMemberAst functionMemberAst)852 {853 var parameterTypes = GetParameterTypes(functionMemberAst);854 if (parameterTypes == null)855 {856 // There must have been an error, just return857 return;858 }859 860 if (CheckForDuplicateOverload(functionMemberAst, parameterTypes))861 {862 return;863 }864 865 if (functionMemberAst.IsConstructor)866 {867 var methodAttributes = Reflection.MethodAttributes.Public;868 if (functionMemberAst.IsStatic)869 {870 var parameters = functionMemberAst.Parameters;871 if (parameters.Count > 0)872 {873 IScriptExtent errorExtent = Parser.ExtentOf(parameters[0], parameters.Last());874 _parser.ReportError(errorExtent,875 nameof(ParserStrings.StaticConstructorCantHaveParameters),876 ParserStrings.StaticConstructorCantHaveParameters);877 return;878 }879 880 methodAttributes |= Reflection.MethodAttributes.Static;881 }882 883 DefineConstructor(functionMemberAst, functionMemberAst.Attributes, functionMemberAst.IsHidden, methodAttributes, parameterTypes);884 return;885 }886 887 var attributes = functionMemberAst.IsPublic888 ? Reflection.MethodAttributes.Public889 : Reflection.MethodAttributes.Private;890 if (functionMemberAst.IsStatic)891 {892 attributes |= Reflection.MethodAttributes.Static;893 }894 else895 {896 if (this.MethodExistsOnBaseClassAndFinal(functionMemberAst.Name, parameterTypes))897 {898 attributes |= Reflection.MethodAttributes.HideBySig;899 attributes |= Reflection.MethodAttributes.NewSlot;900 }901 902 attributes |= Reflection.MethodAttributes.Virtual;903 }904 905 var returnType = functionMemberAst.GetReturnType();906 if (returnType == null)907 {908 _parser.ReportError(functionMemberAst.ReturnType.Extent,909 nameof(ParserStrings.TypeNotFound),910 ParserStrings.TypeNotFound,911 functionMemberAst.ReturnType.TypeName.FullName);912 return;913 }914 915 var method = _typeBuilder.DefineMethod(functionMemberAst.Name, attributes, returnType, parameterTypes);916 DefineCustomAttributes(method, functionMemberAst.Attributes, _parser, AttributeTargets.Method);917 if (functionMemberAst.IsHidden)918 {919 method.SetCustomAttribute(s_hiddenCustomAttributeBuilder);920 }921 922 var ilGenerator = method.GetILGenerator();923 DefineMethodBody(functionMemberAst, ilGenerator, GetMetaDataName(method.Name, parameterTypes.Length), functionMemberAst.IsStatic, parameterTypes, returnType,924 (i, n) => method.DefineParameter(i, ParameterAttributes.None, n));925 }926 927 private void DefineConstructor(IParameterMetadataProvider ipmp, ReadOnlyCollection<AttributeAst> attributeAsts, bool isHidden, Reflection.MethodAttributes methodAttributes, Type[] parameterTypes)928 {929 bool isStatic = (methodAttributes & Reflection.MethodAttributes.Static) != 0;930 var ctor = isStatic931 ? _typeBuilder.DefineTypeInitializer()932 : _typeBuilder.DefineConstructor(methodAttributes, CallingConventions.Standard, parameterTypes);933 DefineCustomAttributes(ctor, attributeAsts, _parser, AttributeTargets.Constructor);934 if (isHidden)935 {936 ctor.SetCustomAttribute(s_hiddenCustomAttributeBuilder);937 }938 939 var ilGenerator = ctor.GetILGenerator();940 941 if (!isStatic)942 {943 ilGenerator.Emit(OpCodes.Ldarg_0); // load 'this' on stack for Stfld call944 945 ilGenerator.Emit(OpCodes.Ldnull);946 ilGenerator.Emit(OpCodes.Ldfld, _sessionStateKeeperField);947 ilGenerator.EmitCall(OpCodes.Call, s_sessionStateKeeper_GetSessionState, null); // load 'sessionState' on stack for Stfld call948 949 ilGenerator.Emit(OpCodes.Stfld, _sessionStateField);950 }951 952 DefineMethodBody(ipmp, ilGenerator, GetMetaDataName(ctor.Name, parameterTypes.Length), isStatic, parameterTypes, typeof(void),953 (i, n) => ctor.DefineParameter(i, ParameterAttributes.None, n));954 }955 956 private static string GetMetaDataName(string name, int numberOfParameters)957 {958 int currentId = Interlocked.Increment(ref s_globalCounter);959 string metaDataName = name + "_" + numberOfParameters + "_" + currentId;960 return metaDataName;961 }962 963 private void DefineMethodBody(964 IParameterMetadataProvider ipmp,965 ILGenerator ilGenerator,966 string metadataToken,967 bool isStatic,968 Type[] parameterTypes,969 Type returnType,970 Action<int, string> parameterNameSetter)971 {972 var wrapperFieldName = string.Create(CultureInfo.InvariantCulture, $"<{metadataToken}>");973 var scriptBlockWrapperField = _staticHelpersTypeBuilder.DefineField(wrapperFieldName,974 typeof(ScriptBlockMemberMethodWrapper),975 FieldAttributes.Assembly | FieldAttributes.Static);976 977 ilGenerator.Emit(OpCodes.Ldsfld, scriptBlockWrapperField);978 if (isStatic)979 {980 ilGenerator.Emit(OpCodes.Ldnull); // pass null (no this)981 ilGenerator.Emit(OpCodes.Ldnull); // pass null (no sessionStateInternal)982 }983 else984 {985 EmitLdarg(ilGenerator, 0); // pass this986 ilGenerator.Emit(OpCodes.Ldarg_0); // pass 'this' for Ldfld call987 ilGenerator.Emit(OpCodes.Ldfld, _sessionStateField); // pass sessionStateInternal988 }989 990 int parameterCount = parameterTypes.Length;991 if (parameterCount > 0)992 {993 var parameters = ipmp.Parameters;994 var local = ilGenerator.DeclareLocal(typeof(object[]));995 996 EmitLdc(ilGenerator, parameterCount); // Create an array to hold all997 ilGenerator.Emit(OpCodes.Newarr, typeof(object)); // of the parameters998 ilGenerator.Emit(OpCodes.Stloc, local); // Save array for repeated use999 int j = isStatic ? 0 : 1;1000 for (int i = 0; i < parameterCount; i++, j++)1001 {1002 ilGenerator.Emit(OpCodes.Ldloc, local); // load array1003 EmitLdc(ilGenerator, i); // index to save at1004 EmitLdarg(ilGenerator, j); // load argument (skipping this)1005 if (parameterTypes[i].IsValueType) // value types must be boxed1006 {1007 ilGenerator.Emit(OpCodes.Box, parameterTypes[i]);1008 }1009 1010 ilGenerator.Emit(OpCodes.Stelem_Ref); // save the argument in the array1011 1012 // Set the parameter name, mostly for Get-Member1013 // Parameters are indexed beginning with the number 1 for the first parameter1014 parameterNameSetter(i + 1, parameters[i].Name.VariablePath.UserPath);1015 }1016 1017 ilGenerator.Emit(OpCodes.Ldloc, local); // load array1018 }1019 else1020 {1021 ilGenerator.Emit(OpCodes.Ldsfld, typeof(ScriptBlockMemberMethodWrapper).GetField("_emptyArgumentArray", BindingFlags.Static | BindingFlags.Public));1022 }1023 1024 MethodInfo invokeHelper;1025 if (returnType == typeof(void))1026 {1027 invokeHelper = typeof(ScriptBlockMemberMethodWrapper).GetMethod("InvokeHelper", BindingFlags.Instance | BindingFlags.Public);1028 }1029 else1030 {1031 invokeHelper = typeof(ScriptBlockMemberMethodWrapper).GetMethod("InvokeHelperT", BindingFlags.Instance | BindingFlags.Public).MakeGenericMethod(returnType);1032 }1033 1034 ilGenerator.Emit(OpCodes.Tailcall);1035 ilGenerator.EmitCall(OpCodes.Call, invokeHelper, null);1036 ilGenerator.Emit(OpCodes.Ret);1037 1038 _fieldsToInitForMemberFunctions.Add((wrapperFieldName, ipmp, isStatic));1039 }1040 }1041 1042 private sealed class DefineEnumHelper1043 {1044 private readonly Parser _parser;1045 private readonly TypeDefinitionAst _enumDefinitionAst;1046 private readonly ModuleBuilder _moduleBuilder;1047 private readonly string _typeName;1048 1049 internal DefineEnumHelper(Parser parser, ModuleBuilder module, TypeDefinitionAst enumDefinitionAst, string typeName)1050 {1051 _parser = parser;1052 _enumDefinitionAst = enumDefinitionAst;1053 _moduleBuilder = module;1054 _typeName = typeName;1055 }1056 1057 internal static List<DefineEnumHelper> Sort(List<DefineEnumHelper> defineEnumHelpers, Parser parser)1058 {1059 // This function does a topological sort of the enums to be defined. This is needed so we1060 // can allow one enum member to use the value of another w/o needing to worry about the order1061 // they are declared in. For example:1062 //1063 // enum E1 { e1 = [E2]::e2 }1064 // enum E2 { e2 = 42 }1065 //1066 // We also want to report an error for recursive expressions, e.g.1067 //1068 // enum E1 { e1 = [E2]::e2 }1069 // enum E2 { e2 = [E1]::e1 }1070 //1071 // Note that this code is not as permissive as it could be, e.g. we could (but do not) allow:1072 //1073 // enum E1 { e1 = [E2]::e2 }1074 // enum E2 {1075 // e2 = 421076 // e2a = [E1]::e11077 // }1078 //1079 // In this case, there is no cycle in the constant values despite E1 referencing E2 and vice versa.1080 //1081 // The basic algorithm is to create a graph where the edges represent a dependency, using this example:1082 //1083 // enum E1 { e1 = [E2]::e2 }1084 // enum E2 { e2 = 42 }1085 //1086 // We have an edge E1->E2. E2 has no dependencies.1087 1088 if (defineEnumHelpers.Count == 1)1089 {1090 return defineEnumHelpers;1091 }1092 1093 // There won't be many nodes in our graph, so we just use a dictionary with a list of edges instead1094 // of something cleaner.1095 var graph = new Dictionary<TypeDefinitionAst, Tuple<DefineEnumHelper, List<TypeDefinitionAst>>>();1096 1097 // Add all of our nodes to the graph1098 foreach (var helper in defineEnumHelpers)1099 {1100 graph.Add(helper._enumDefinitionAst, Tuple.Create(helper, new List<TypeDefinitionAst>()));1101 }1102 1103 // Now find any edges.1104 foreach (var helper in defineEnumHelpers)1105 {1106 foreach (var enumerator in helper._enumDefinitionAst.Members)1107 {1108 var initExpr = ((PropertyMemberAst)enumerator).InitialValue;1109 if (initExpr == null)1110 {1111 // No initializer, so no dependency (this is incorrect assumption if1112 // we wanted to be more general like C#.)1113 continue;1114 }1115 1116 // The expression may have multiple member expressions, e.g. [E]::e1 + [E]::e21117 foreach (var memberExpr in initExpr.FindAll(static ast => ast is MemberExpressionAst, false))1118 {1119 var typeExpr = ((MemberExpressionAst)memberExpr).Expression as TypeExpressionAst;1120 if (typeExpr != null)1121 {1122 // We only want to add edges for enums being defined in the current scope.1123 // We detect this by seeing if the ast is in our graph or not.1124 var typeName = typeExpr.TypeName as TypeName;1125 if (typeName != null1126 && typeName._typeDefinitionAst != null1127 && typeName._typeDefinitionAst != helper._enumDefinitionAst // Don't add self edges1128 && graph.ContainsKey(typeName._typeDefinitionAst))1129 {1130 var edgeList = graph[helper._enumDefinitionAst].Item2;1131 if (!edgeList.Contains(typeName._typeDefinitionAst)) // Only add 1 edge per enum1132 {1133 edgeList.Add(typeName._typeDefinitionAst);1134 }1135 }1136 }1137 }1138 }1139 }1140 1141 // Our graph is built. The ready list will hold nodes that don't depend on anything not already1142 // in the result list. We start with a list of nodes with no edges (no dependencies).1143 var result = new List<DefineEnumHelper>(defineEnumHelpers.Count);1144 var readyList = new List<DefineEnumHelper>(defineEnumHelpers.Count);1145 readyList.AddRange(from value in graph.Values where value.Item2.Count == 0 select value.Item1);1146 while (readyList.Count > 0)1147 {1148 var node = readyList[readyList.Count - 1];1149 readyList.RemoveAt(readyList.Count - 1);1150 result.Add(node);1151 1152 // Remove all edges to this node as it is in our result list now.1153 foreach (var value in graph.Values)1154 {1155 value.Item2.Remove(node._enumDefinitionAst);1156 1157 // If we removed the last edge, we can put this node on the ready list (assuming it1158 // wasn't already there or in our result list.)1159 if (value.Item2.Count == 0 && !result.Contains(value.Item1) && !readyList.Contains(value.Item1))1160 {1161 readyList.Add(value.Item1);1162 }1163 }1164 }1165 1166 if (result.Count < defineEnumHelpers.Count)1167 {1168 // There was a cycle, report an error on each enum.1169 foreach (var helper in defineEnumHelpers)1170 {1171 if (!result.Contains(helper))1172 {1173 parser.ReportError(helper._enumDefinitionAst.Extent,1174 nameof(ParserStrings.CycleInEnumInitializers),1175 ParserStrings.CycleInEnumInitializers);1176 }1177 }1178 }1179 else1180 {1181 Diagnostics.Assert(result.Count == defineEnumHelpers.Count, "Logic error if we have more outgoing results than incoming");1182 }1183 1184 return result;1185 }1186 1187 internal void DefineEnum()1188 {1189 var typeConstraintAst = _enumDefinitionAst.BaseTypes.FirstOrDefault();1190 var underlyingType = typeConstraintAst == null ? typeof(int) : typeConstraintAst.TypeName.GetReflectionType();1191 1192 var definedEnumerators = new HashSet<string>(StringComparer.OrdinalIgnoreCase);1193 var enumBuilder = _moduleBuilder.DefineEnum(_typeName, Reflection.TypeAttributes.Public, underlyingType);1194 DefineCustomAttributes(enumBuilder, _enumDefinitionAst.Attributes, _parser, AttributeTargets.Enum);1195 1196 dynamic value = 0;1197 dynamic maxValue = 0;1198 switch (Type.GetTypeCode(underlyingType))1199 {1200 case TypeCode.Byte: