public override ParameterMetadata[] GetParameterMetadata() { MetadataReader metadataReader = MetadataReader; // Spot check the enums match Debug.Assert((int)ParameterAttributes.In == (int)ParameterMetadataAttributes.In); Debug.Assert((int)ParameterAttributes.Out == (int)ParameterMetadataAttributes.Out); Debug.Assert((int)ParameterAttributes.Optional == (int)ParameterMetadataAttributes.Optional); Debug.Assert((int)ParameterAttributes.HasDefault == (int)ParameterMetadataAttributes.HasDefault); Debug.Assert((int)ParameterAttributes.HasFieldMarshal == (int)ParameterMetadataAttributes.HasFieldMarshal); ParameterHandleCollection parameterHandles = metadataReader.GetMethodDefinition(_handle).GetParameters(); ParameterMetadata[] parameterMetadataArray = new ParameterMetadata[parameterHandles.Count]; int index = 0; foreach (ParameterHandle parameterHandle in parameterHandles) { Parameter parameter = metadataReader.GetParameter(parameterHandle); MarshalAsDescriptor marshalAsDescriptor = GetMarshalAsDescriptor(parameter); ParameterMetadata data = new ParameterMetadata(parameter.SequenceNumber, (ParameterMetadataAttributes)parameter.Attributes, marshalAsDescriptor); parameterMetadataArray[index++] = data; } return(parameterMetadataArray); }
} // Read public static uint Read(this NativeReader reader, uint offset, out ParameterHandleCollection values) { values = new ParameterHandleCollection(reader, offset); uint count; offset = reader.DecodeUnsigned(offset, out count); for (uint i = 0; i < count; ++i) { offset = reader.SkipInteger(offset); } return(offset); } // Read
private IEnumerable <ParameterInfo> GetParams(ParameterHandleCollection parameterHandles) { foreach (var pH in parameterHandles) { var p = this.metadataReader.GetParameter(pH); string pName = this.metadataReader.GetString(p.Name); if (!string.IsNullOrEmpty(pName)) { yield return(new ParameterInfo(pName, p.Attributes)); } } }
public IEnumerable <string> GetParameterNamesForMethod(MethodDesc method) { EcmaMethod ecmaMethod = method.GetTypicalMethodDefinition() as EcmaMethod; if (ecmaMethod == null) { yield break; } ParameterHandleCollection parameters = ecmaMethod.MetadataReader.GetMethodDefinition(ecmaMethod.Handle).GetParameters(); if (!ecmaMethod.Signature.IsStatic) { yield return("_this"); } foreach (var parameterHandle in parameters) { Parameter p = ecmaMethod.MetadataReader.GetParameter(parameterHandle); yield return(ecmaMethod.MetadataReader.GetString(p.Name)); } }
public override IEnumerable <string> GetParameterNames() { ParameterHandleCollection parameters = _method.MetadataReader.GetMethodDefinition(_method.Handle).GetParameters(); if (!_method.Signature.IsStatic) { // TODO: this name might conflict with a parameter name or a local name. We need something unique. yield return("___this"); } // TODO: The Params table is allowed to have holes in it. This expect all parameters to be present. foreach (var parameterHandle in parameters) { Parameter p = _method.MetadataReader.GetParameter(parameterHandle); // Parameter with sequence number 0 refers to the return parameter if (p.SequenceNumber == 0) { continue; } yield return(_method.MetadataReader.GetString(p.Name)); } }
internal static CilParameter[] DecodeParameters(MethodSignature <CilType> signature, ParameterHandleCollection parameters, ref CilReaders readers) { ImmutableArray <CilType> types = signature.ParameterTypes; int requiredCount = Math.Min(signature.RequiredParameterCount, types.Length); if (requiredCount == 0) { return(new CilParameter[0]); } CilParameter[] result = new CilParameter[requiredCount]; for (int i = 0; i < requiredCount; i++) { var parameter = readers.MdReader.GetParameter(parameters.ElementAt(i)); result[i] = CilParameter.Create(parameter, ref readers, types[i].ToString()); } return(result); }
protected override TypeAnnotations CreateValueFromKey(TypeDesc key) { // We scan the entire type at this point; the reason for doing that is properties. // // We allow annotating properties, but those annotations need to flow onto individual get/set methods // and backing fields. Without scanning all properties, we can't answer questions about fields/methods. // And if we're going over all properties, we might as well go over everything else to keep things simple. Debug.Assert(key.IsTypeDefinition); if (key is not EcmaType ecmaType) { return(new TypeAnnotations(key, DynamicallyAccessedMemberTypes.None, null, null, null)); } MetadataReader reader = ecmaType.MetadataReader; // class, interface, struct can have annotations TypeDefinition typeDef = reader.GetTypeDefinition(ecmaType.Handle); DynamicallyAccessedMemberTypes typeAnnotation = GetMemberTypesForDynamicallyAccessedMembersAttribute(reader, typeDef.GetCustomAttributes()); try { // Also inherit annotation from bases TypeDesc baseType = key.BaseType; while (baseType != null) { TypeDefinition baseTypeDef = reader.GetTypeDefinition(((EcmaType)baseType.GetTypeDefinition()).Handle); typeAnnotation |= GetMemberTypesForDynamicallyAccessedMembersAttribute(reader, baseTypeDef.GetCustomAttributes()); baseType = baseType.BaseType; } // And inherit them from interfaces foreach (DefType runtimeInterface in key.RuntimeInterfaces) { TypeDefinition interfaceTypeDef = reader.GetTypeDefinition(((EcmaType)runtimeInterface.GetTypeDefinition()).Handle); typeAnnotation |= GetMemberTypesForDynamicallyAccessedMembersAttribute(reader, interfaceTypeDef.GetCustomAttributes()); } } catch (TypeSystemException) { // If the class hierarchy is not walkable, just stop collecting the annotations. } var annotatedFields = new ArrayBuilder <FieldAnnotation>(); // First go over all fields with an explicit annotation foreach (EcmaField field in ecmaType.GetFields()) { FieldDefinition fieldDef = reader.GetFieldDefinition(field.Handle); DynamicallyAccessedMemberTypes annotation = GetMemberTypesForDynamicallyAccessedMembersAttribute(reader, fieldDef.GetCustomAttributes()); if (annotation == DynamicallyAccessedMemberTypes.None) { continue; } if (!IsTypeInterestingForDataflow(field.FieldType)) { // Already know that there's a non-empty annotation on a field which is not System.Type/String and we're about to ignore it _logger.LogWarning(field, DiagnosticId.DynamicallyAccessedMembersOnFieldCanOnlyApplyToTypesOrStrings, field.GetDisplayName()); continue; } annotatedFields.Add(new FieldAnnotation(field, annotation)); } var annotatedMethods = new ArrayBuilder <MethodAnnotations>(); // Next go over all methods with an explicit annotation foreach (EcmaMethod method in ecmaType.GetMethods()) { DynamicallyAccessedMemberTypes[]? paramAnnotations = null; // We convert indices from metadata space to IL space here. // IL space assigns index 0 to the `this` parameter on instance methods. DynamicallyAccessedMemberTypes methodMemberTypes = GetMemberTypesForDynamicallyAccessedMembersAttribute(reader, reader.GetMethodDefinition(method.Handle).GetCustomAttributes()); MethodSignature signature; try { signature = method.Signature; } catch (TypeSystemException) { // If we cannot resolve things in the signature, just move along. continue; } int offset; if (!signature.IsStatic) { offset = 1; } else { offset = 0; } // If there's an annotation on the method itself and it's one of the special types (System.Type for example) // treat that annotation as annotating the "this" parameter. if (methodMemberTypes != DynamicallyAccessedMemberTypes.None) { if (IsTypeInterestingForDataflow(method.OwningType) && !signature.IsStatic) { paramAnnotations = new DynamicallyAccessedMemberTypes[signature.Length + offset]; paramAnnotations[0] = methodMemberTypes; } else { _logger.LogWarning(method, DiagnosticId.DynamicallyAccessedMembersIsNotAllowedOnMethods); } } MethodDefinition methodDef = reader.GetMethodDefinition(method.Handle); ParameterHandleCollection parameterHandles = methodDef.GetParameters(); DynamicallyAccessedMemberTypes returnAnnotation = DynamicallyAccessedMemberTypes.None; foreach (ParameterHandle parameterHandle in parameterHandles) { Parameter parameter = reader.GetParameter(parameterHandle); if (parameter.SequenceNumber == 0) { // this is the return parameter returnAnnotation = GetMemberTypesForDynamicallyAccessedMembersAttribute(reader, parameter.GetCustomAttributes()); if (returnAnnotation != DynamicallyAccessedMemberTypes.None && !IsTypeInterestingForDataflow(signature.ReturnType)) { _logger.LogWarning(method, DiagnosticId.DynamicallyAccessedMembersOnMethodReturnValueCanOnlyApplyToTypesOrStrings, method.GetDisplayName()); } } else { DynamicallyAccessedMemberTypes pa = GetMemberTypesForDynamicallyAccessedMembersAttribute(reader, parameter.GetCustomAttributes()); if (pa == DynamicallyAccessedMemberTypes.None) { continue; } if (!IsTypeInterestingForDataflow(signature[parameter.SequenceNumber - 1])) { _logger.LogWarning(method, DiagnosticId.DynamicallyAccessedMembersOnMethodParameterCanOnlyApplyToTypesOrStrings, DiagnosticUtilities.GetParameterNameForErrorMessage(method, parameter.SequenceNumber - 1), method.GetDisplayName()); continue; } if (paramAnnotations == null) { paramAnnotations = new DynamicallyAccessedMemberTypes[signature.Length + offset]; } paramAnnotations[parameter.SequenceNumber - 1 + offset] = pa; } } DynamicallyAccessedMemberTypes[]? genericParameterAnnotations = null; foreach (EcmaGenericParameter genericParameter in method.Instantiation) { GenericParameter genericParameterDef = reader.GetGenericParameter(genericParameter.Handle); var annotation = GetMemberTypesForDynamicallyAccessedMembersAttribute(reader, genericParameterDef.GetCustomAttributes()); if (annotation != DynamicallyAccessedMemberTypes.None) { if (genericParameterAnnotations == null) { genericParameterAnnotations = new DynamicallyAccessedMemberTypes[method.Instantiation.Length]; } genericParameterAnnotations[genericParameter.Index] = annotation; } } if (returnAnnotation != DynamicallyAccessedMemberTypes.None || paramAnnotations != null || genericParameterAnnotations != null) { annotatedMethods.Add(new MethodAnnotations(method, paramAnnotations, returnAnnotation, genericParameterAnnotations)); } } // Next up are properties. Annotations on properties are kind of meta because we need to // map them to annotations on methods/fields. They're syntactic sugar - what they do is expressible // by placing attribute on the accessor/backing field. For complex properties, that's what people // will need to do anyway. Like so: // // [field: Attribute] // Type MyProperty // { // [return: Attribute] // get; // [value: Attribute] // set; // } foreach (PropertyDefinitionHandle propertyHandle in reader.GetTypeDefinition(ecmaType.Handle).GetProperties()) { DynamicallyAccessedMemberTypes annotation = GetMemberTypesForDynamicallyAccessedMembersAttribute( reader, reader.GetPropertyDefinition(propertyHandle).GetCustomAttributes()); if (annotation == DynamicallyAccessedMemberTypes.None) { continue; } PropertyPseudoDesc property = new PropertyPseudoDesc(ecmaType, propertyHandle); if (!IsTypeInterestingForDataflow(property.Signature.ReturnType)) { _logger.LogWarning(property, DiagnosticId.DynamicallyAccessedMembersOnPropertyCanOnlyApplyToTypesOrStrings, property.GetDisplayName()); continue; } FieldDesc?backingFieldFromSetter = null; // Propagate the annotation to the setter method MethodDesc setMethod = property.SetMethod; if (setMethod != null) { // Abstract property backing field propagation doesn't make sense, and any derived property will be validated // to have the exact same annotations on getter/setter, and thus if it has a detectable backing field that will be validated as well. MethodIL methodBody = _ilProvider.GetMethodIL(setMethod); if (methodBody != null) { // Look for the compiler generated backing field. If it doesn't work out simply move on. In such case we would still // propagate the annotation to the setter/getter and later on when analyzing the setter/getter we will warn // that the field (which ever it is) must be annotated as well. ScanMethodBodyForFieldAccess(methodBody, write: true, out backingFieldFromSetter); } if (annotatedMethods.Any(a => a.Method == setMethod)) { _logger.LogWarning(setMethod, DiagnosticId.DynamicallyAccessedMembersConflictsBetweenPropertyAndAccessor, property.GetDisplayName(), setMethod.GetDisplayName()); } else { int offset = setMethod.Signature.IsStatic ? 0 : 1; if (setMethod.Signature.Length > 0) { DynamicallyAccessedMemberTypes[] paramAnnotations = new DynamicallyAccessedMemberTypes[setMethod.Signature.Length + offset]; paramAnnotations[paramAnnotations.Length - 1] = annotation; annotatedMethods.Add(new MethodAnnotations(setMethod, paramAnnotations, DynamicallyAccessedMemberTypes.None, null)); } } } FieldDesc?backingFieldFromGetter = null; // Propagate the annotation to the getter method MethodDesc getMethod = property.GetMethod; if (getMethod != null) { // Abstract property backing field propagation doesn't make sense, and any derived property will be validated // to have the exact same annotations on getter/setter, and thus if it has a detectable backing field that will be validated as well. MethodIL methodBody = _ilProvider.GetMethodIL(getMethod); if (methodBody != null) { // Look for the compiler generated backing field. If it doesn't work out simply move on. In such case we would still // propagate the annotation to the setter/getter and later on when analyzing the setter/getter we will warn // that the field (which ever it is) must be annotated as well. ScanMethodBodyForFieldAccess(methodBody, write: false, out backingFieldFromGetter); } if (annotatedMethods.Any(a => a.Method == getMethod)) { _logger.LogWarning(getMethod, DiagnosticId.DynamicallyAccessedMembersConflictsBetweenPropertyAndAccessor, property.GetDisplayName(), getMethod.GetDisplayName()); } else { annotatedMethods.Add(new MethodAnnotations(getMethod, null, annotation, null)); } } FieldDesc?backingField; if (backingFieldFromGetter != null && backingFieldFromSetter != null && backingFieldFromGetter != backingFieldFromSetter) { _logger.LogWarning(property, DiagnosticId.DynamicallyAccessedMembersCouldNotFindBackingField, property.GetDisplayName()); backingField = null; } else { backingField = backingFieldFromGetter ?? backingFieldFromSetter; } if (backingField != null) { if (annotatedFields.Any(a => a.Field == backingField)) { _logger.LogWarning(backingField, DiagnosticId.DynamicallyAccessedMembersOnPropertyConflictsWithBackingField, property.GetDisplayName(), backingField.GetDisplayName()); } else { annotatedFields.Add(new FieldAnnotation(backingField, annotation)); } } } DynamicallyAccessedMemberTypes[]? typeGenericParameterAnnotations = null; foreach (EcmaGenericParameter genericParameter in ecmaType.Instantiation) { GenericParameter genericParameterDef = reader.GetGenericParameter(genericParameter.Handle); var annotation = GetMemberTypesForDynamicallyAccessedMembersAttribute(reader, genericParameterDef.GetCustomAttributes()); if (annotation != DynamicallyAccessedMemberTypes.None) { if (typeGenericParameterAnnotations == null) { typeGenericParameterAnnotations = new DynamicallyAccessedMemberTypes[ecmaType.Instantiation.Length]; } typeGenericParameterAnnotations[genericParameter.Index] = annotation; } } return(new TypeAnnotations(ecmaType, typeAnnotation, annotatedMethods.ToArray(), annotatedFields.ToArray(), typeGenericParameterAnnotations)); }
} // Read public static uint Read(this NativeReader reader, uint offset, out ParameterHandleCollection values) { values = new ParameterHandleCollection(reader, offset); uint count; offset = reader.DecodeUnsigned(offset, out count); for (uint i = 0; i < count; ++i) { offset = reader.SkipInteger(offset); } return offset; } // Read
internal static CilParameter[] DecodeParameters(MethodSignature<CilType> signature, ParameterHandleCollection parameters, ref CilReaders readers) { ImmutableArray<CilType> types = signature.ParameterTypes; int requiredCount = Math.Min(signature.RequiredParameterCount, types.Length); if (requiredCount == 0) { return new CilParameter[0]; } CilParameter[] result = new CilParameter[requiredCount]; for (int i = 0; i < requiredCount; i++) { var parameter = readers.MdReader.GetParameter(parameters.ElementAt(i)); result[i] = CilParameter.Create(parameter, ref readers, types[i].ToString()); } return result; }
GetParameters(MetadataReader reader, TypeReferenceTypeProvider typeProvider, GenericContext genericContext, MethodSignature <MetadataTypeReference> signature, ParameterHandleCollection handles) { var parameters = new IMetadataParameter[handles.Count]; var returnValueAttributes = (IReadOnlyList <IMetadataAttribute>)null; var maxSequenceNumber = 0; foreach (var handle in handles) { var parameter = reader.GetParameter(handle); if (parameter.SequenceNumber == 0) { returnValueAttributes = GetAttributes(reader, typeProvider, parameter.GetCustomAttributes(), genericContext); continue; } if (maxSequenceNumber < parameter.SequenceNumber) { maxSequenceNumber = parameter.SequenceNumber; } var parameterIndex = parameter.SequenceNumber - 1; parameters[parameterIndex] = new ReaderParameter(reader, typeProvider, parameter, genericContext, signature.ParameterTypes[parameterIndex]); } if (maxSequenceNumber == parameters.Length) { return(parameters, Array.Empty <IMetadataAttribute>()); } // Account for skipping the return parameter var correctedLength = new IMetadataParameter[maxSequenceNumber]; Array.Copy(parameters, correctedLength, correctedLength.Length); return(correctedLength, returnValueAttributes); }