private static void AddDependenciesDueToCustomAttributes(ref DependencyList dependencies, NodeFactory factory, EcmaModule module, CustomAttributeHandleCollection attributeHandles) { MetadataReader reader = module.MetadataReader; var mdManager = (UsageBasedMetadataManager)factory.MetadataManager; var attributeTypeProvider = new CustomAttributeTypeProvider(module); foreach (CustomAttributeHandle caHandle in attributeHandles) { CustomAttribute attribute = reader.GetCustomAttribute(caHandle); try { MethodDesc constructor = module.GetMethod(attribute.Constructor); if (!mdManager.GeneratesAttributeMetadata(constructor.OwningType)) { continue; } if (mdManager.IsReflectionBlocked(constructor)) { continue; } CustomAttributeValue <TypeDesc> decodedValue = attribute.DecodeValue(attributeTypeProvider); // Make a new list in case we need to abort. var caDependencies = factory.MetadataManager.GetDependenciesForCustomAttribute(factory, constructor, decodedValue) ?? new DependencyList(); caDependencies.Add(factory.ReflectableMethod(constructor), "Attribute constructor"); caDependencies.Add(factory.ConstructedTypeSymbol(constructor.OwningType), "Attribute type"); if (AddDependenciesFromCustomAttributeBlob(caDependencies, factory, constructor.OwningType, decodedValue)) { dependencies = dependencies ?? new DependencyList(); dependencies.AddRange(caDependencies); dependencies.Add(factory.CustomAttributeMetadata(new ReflectableCustomAttribute(module, caHandle)), "Attribute metadata"); } } catch (TypeSystemException) { // We could end up seeing an exception here for a multitude of reasons: // * Attribute ctor doesn't resolve // * There's a typeof() that refers to something that can't be loaded // * Attribute refers to a non-existing field // * Etc. // // If we really wanted to, we could probably come up with a way to still make this // work with the same failure modes at runtime as the CLR, but it might not be // worth the hassle: the input was invalid. The most important thing is that we // don't crash the compilation. } } }
public void TestCustomAttributeDecoderGenericArray() { Type type = typeof(HasGenericArrayAttributes); using (FileStream stream = File.OpenRead(AssemblyPathHelper.GetAssemblyLocation(type.GetTypeInfo().Assembly))) using (PEReader peReader = new PEReader(stream)) { MetadataReader reader = peReader.GetMetadataReader(); CustomAttributeTypeProvider provider = new CustomAttributeTypeProvider(); TypeDefinitionHandle typeDefHandle = TestMetadataResolver.FindTestType(reader, type); IList <CustomAttributeData> attributes = type.GetCustomAttributesData(); foreach (CustomAttributeHandle attributeHandle in reader.GetCustomAttributes(typeDefHandle)) { CustomAttribute attribute = reader.GetCustomAttribute(attributeHandle); CustomAttributeValue <string> value = attribute.DecodeValue(provider); if (value.FixedArguments.Length == 2) { Assert.Equal(2, value.FixedArguments.Length); ImmutableArray <CustomAttributeTypedArgument <string> > array1 = (ImmutableArray <CustomAttributeTypedArgument <string> >)(value.FixedArguments[0].Value); Assert.Equal("int32[]", value.FixedArguments[0].Type); Assert.Equal(1, array1[0].Value); Assert.Equal(3, array1[2].Value); ImmutableArray <CustomAttributeTypedArgument <string> > array2 = (ImmutableArray <CustomAttributeTypedArgument <string> >)(value.FixedArguments[1].Value); Assert.Equal("uint8[]", value.FixedArguments[1].Type); Assert.Equal((byte)4, array2[0].Value); Assert.Equal((byte)5, array2[1].Value); Assert.Empty(value.NamedArguments); } else { Assert.Equal(1, value.FixedArguments.Length); Assert.Equal("uint8", value.FixedArguments[0].Type); Assert.Equal((byte)1, value.FixedArguments[0].Value); Assert.Equal(2, value.NamedArguments.Length); Assert.Equal("uint8", value.NamedArguments[0].Type); Assert.Equal((byte)2, value.NamedArguments[0].Value); ImmutableArray <CustomAttributeTypedArgument <string> > array = (ImmutableArray <CustomAttributeTypedArgument <string> >)(value.NamedArguments[1].Value); Assert.Equal("uint8[]", value.NamedArguments[1].Type); Assert.Equal((byte)3, array[0].Value); } } } }
public void TestCustomAttributeDecoderGenericUsingReflection() { Type type = typeof(HasGenericAttributes); using (FileStream stream = File.OpenRead(AssemblyPathHelper.GetAssemblyLocation(type.GetTypeInfo().Assembly))) using (PEReader peReader = new PEReader(stream)) { MetadataReader reader = peReader.GetMetadataReader(); CustomAttributeTypeProvider provider = new CustomAttributeTypeProvider(); TypeDefinitionHandle typeDefHandle = TestMetadataResolver.FindTestType(reader, type); IList <CustomAttributeData> attributes = type.GetCustomAttributesData(); int i = 0; foreach (CustomAttributeHandle attributeHandle in reader.GetCustomAttributes(typeDefHandle)) { CustomAttribute attribute = reader.GetCustomAttribute(attributeHandle); CustomAttributeValue <string> value = attribute.DecodeValue(provider); CustomAttributeData reflectionAttribute = attributes[i++]; Assert.Equal(reflectionAttribute.ConstructorArguments.Count, value.FixedArguments.Length); Assert.Equal(reflectionAttribute.NamedArguments.Count, value.NamedArguments.Length); int j = 0; foreach (CustomAttributeTypedArgument <string> arguments in value.FixedArguments) { Assert.Equal(TypeToString(reflectionAttribute.ConstructorArguments[j].ArgumentType), arguments.Type); if (reflectionAttribute.ConstructorArguments[j].Value.ToString() != arguments.Value.ToString()) { Assert.Equal(reflectionAttribute.ConstructorArguments[j].Value, arguments.Value); } j++; } j = 0; foreach (CustomAttributeNamedArgument <string> arguments in value.NamedArguments) { Assert.Equal(TypeToString(reflectionAttribute.NamedArguments[j].TypedValue.ArgumentType), arguments.Type); if (reflectionAttribute.NamedArguments[j].TypedValue.Value.ToString() != arguments.Value.ToString()) { Assert.Equal(reflectionAttribute.NamedArguments[j].TypedValue.Value, arguments.Value); } j++; } } } }
/// <summary> /// Gets a value indicating whether '<paramref name="module"/>' is a framework assembly. /// </summary> public static bool IsFrameworkAssembly(EcmaModule module) { MetadataReader reader = module.MetadataReader; // We look for [assembly:AssemblyMetadata(".NETFrameworkAssembly", "")] foreach (CustomAttributeHandle attributeHandle in reader.GetAssemblyDefinition().GetCustomAttributes()) { if (!reader.GetAttributeNamespaceAndName(attributeHandle, out StringHandle namespaceHandle, out StringHandle nameHandle)) { continue; } if (!reader.StringComparer.Equals(namespaceHandle, "System.Reflection") || !reader.StringComparer.Equals(nameHandle, "AssemblyMetadataAttribute")) { continue; } var attributeTypeProvider = new CustomAttributeTypeProvider(module); CustomAttribute attribute = reader.GetCustomAttribute(attributeHandle); CustomAttributeValue <TypeDesc> decodedAttribute = attribute.DecodeValue(attributeTypeProvider); if (decodedAttribute.FixedArguments.Length != 2) { continue; } if (decodedAttribute.FixedArguments[0].Value is string s && s == ".NETFrameworkAssembly") { return(true); } } return(false); }
public void TestCustomAttributeDecoderUsingReflection() { Type type = typeof(HasAttributes); using (FileStream stream = File.OpenRead(AssemblyPathHelper.GetAssemblyLocation(type.GetTypeInfo().Assembly))) using (PEReader peReader = new PEReader(stream)) { MetadataReader reader = peReader.GetMetadataReader(); CustomAttributeTypeProvider provider = new CustomAttributeTypeProvider(); TypeDefinitionHandle typeDefHandle = TestMetadataResolver.FindTestType(reader, type); IList <CustomAttributeData> attributes = type.GetCustomAttributesData(); int i = 0; foreach (CustomAttributeHandle attributeHandle in reader.GetCustomAttributes(typeDefHandle)) { CustomAttribute attribute = reader.GetCustomAttribute(attributeHandle); CustomAttributeValue <string> value = attribute.DecodeValue(provider); CustomAttributeData reflectionAttribute = attributes[i++]; Assert.Equal(reflectionAttribute.ConstructorArguments.Count, value.FixedArguments.Length); Assert.Equal(reflectionAttribute.NamedArguments.Count, value.NamedArguments.Length); int j = 0; foreach (CustomAttributeTypedArgument <string> arguments in value.FixedArguments) { Type t = reflectionAttribute.ConstructorArguments[j].ArgumentType; Assert.Equal(TypeToString(t), arguments.Type); if (t.IsArray && arguments.Value is not null) { ImmutableArray <CustomAttributeTypedArgument <string> > array = (ImmutableArray <CustomAttributeTypedArgument <string> >)(arguments.Value); IList <CustomAttributeTypedArgument> refArray = (IList <CustomAttributeTypedArgument>)reflectionAttribute.ConstructorArguments[j].Value; int k = 0; foreach (CustomAttributeTypedArgument <string> element in array) { if (refArray[k].ArgumentType.IsArray) { ImmutableArray <CustomAttributeTypedArgument <string> > innerArray = (ImmutableArray <CustomAttributeTypedArgument <string> >)(element.Value); IList <CustomAttributeTypedArgument> refInnerArray = (IList <CustomAttributeTypedArgument>)refArray[k].Value; int a = 0; foreach (CustomAttributeTypedArgument <string> el in innerArray) { if (refInnerArray[a].Value?.ToString() != el.Value?.ToString()) { Assert.Equal(refInnerArray[a].Value, el.Value); } a++; } } else if (refArray[k].Value?.ToString() != element.Value?.ToString()) { if (refArray[k].ArgumentType == typeof(Type)) // TODO: check if it is expected { Assert.Contains(refArray[k].Value.ToString(), element.Value.ToString()); } else { Assert.Equal(refArray[k].Value, element.Value); } } k++; } } else if (reflectionAttribute.ConstructorArguments[j].Value?.ToString() != arguments.Value?.ToString()) { if (reflectionAttribute.ConstructorArguments[j].ArgumentType == typeof(Type)) { Assert.Contains(reflectionAttribute.ConstructorArguments[j].Value.ToString(), arguments.Value.ToString()); } else { Assert.Equal(reflectionAttribute.ConstructorArguments[j].Value, arguments.Value); } } j++; } j = 0; foreach (CustomAttributeNamedArgument <string> arguments in value.NamedArguments) { Type t = reflectionAttribute.NamedArguments[j].TypedValue.ArgumentType; Assert.Equal(TypeToString(t), arguments.Type); if (t.IsArray && arguments.Value is not null) { ImmutableArray <CustomAttributeTypedArgument <string> > array = (ImmutableArray <CustomAttributeTypedArgument <string> >)(arguments.Value); IList <CustomAttributeTypedArgument> refArray = (IList <CustomAttributeTypedArgument>)reflectionAttribute.NamedArguments[j].TypedValue.Value; int k = 0; foreach (CustomAttributeTypedArgument <string> element in array) { if (refArray[k].Value?.ToString() != element.Value?.ToString()) { Assert.Equal(refArray[k].Value, element.Value); } k++; } } else if (reflectionAttribute.NamedArguments[j].TypedValue.Value?.ToString() != arguments.Value?.ToString()) { if (reflectionAttribute.NamedArguments[j].TypedValue.ArgumentType == typeof(Type)) // typeof operator used for named parameter, like [Test(TypeField = typeof(string))], check if it is expected { Assert.Contains(reflectionAttribute.NamedArguments[j].TypedValue.Value.ToString(), arguments.Value.ToString()); } else { Assert.Equal(reflectionAttribute.NamedArguments[j].TypedValue.Value, arguments.Value); } } j++; } } } }
public void TestCustomAttributeDecoder() { using (FileStream stream = File.OpenRead(AssemblyPathHelper.GetAssemblyLocation(typeof(HasAttributes).GetTypeInfo().Assembly))) using (var peReader = new PEReader(stream)) { MetadataReader reader = peReader.GetMetadataReader(); var provider = new CustomAttributeTypeProvider(); TypeDefinitionHandle typeDefHandle = TestMetadataResolver.FindTestType(reader, typeof(HasAttributes)); int i = 0; foreach (CustomAttributeHandle attributeHandle in reader.GetCustomAttributes(typeDefHandle)) { CustomAttribute attribute = reader.GetCustomAttribute(attributeHandle); CustomAttributeValue <string> value = attribute.DecodeValue(provider); switch (i++) { case 0: Assert.Empty(value.FixedArguments); Assert.Empty(value.NamedArguments); break; case 1: Assert.Equal(3, value.FixedArguments.Length); Assert.Equal("string", value.FixedArguments[0].Type); Assert.Equal("0", value.FixedArguments[0].Value); Assert.Equal("int32", value.FixedArguments[1].Type); Assert.Equal(1, value.FixedArguments[1].Value); Assert.Equal("float64", value.FixedArguments[2].Type); Assert.Equal(2.0, value.FixedArguments[2].Value); Assert.Empty(value.NamedArguments); break; case 2: Assert.Equal(3, value.NamedArguments.Length); Assert.Equal(CustomAttributeNamedArgumentKind.Field, value.NamedArguments[0].Kind); Assert.Equal("StringField", value.NamedArguments[0].Name); Assert.Equal("string", value.NamedArguments[0].Type); Assert.Equal("0", value.NamedArguments[0].Value); Assert.Equal(CustomAttributeNamedArgumentKind.Field, value.NamedArguments[1].Kind); Assert.Equal("Int32Field", value.NamedArguments[1].Name); Assert.Equal("int32", value.NamedArguments[1].Type); Assert.Equal(1, value.NamedArguments[1].Value); Assert.Equal(CustomAttributeNamedArgumentKind.Property, value.NamedArguments[2].Kind); Assert.Equal("SByteEnumArrayProperty", value.NamedArguments[2].Name); Assert.Equal(typeof(SByteEnum).FullName + "[]", value.NamedArguments[2].Type); var array = (ImmutableArray <CustomAttributeTypedArgument <string> >)(value.NamedArguments[2].Value); Assert.Equal(1, array.Length); Assert.Equal(typeof(SByteEnum).FullName, array[0].Type); Assert.Equal((sbyte)SByteEnum.Value, array[0].Value); break; default: // TODO: https://github.com/dotnet/runtime/issues/73593 // This method only tests first 3 attriubtes because the complete test 'TestCustomAttributeDecoderUsingReflection' fails on mono // Leaving this hard coded test only for mono, until the issue fixed on mono break; } } } }
public void TestCustomAttributeDecoder() { using (FileStream stream = File.OpenRead(typeof(HasAttributes).GetTypeInfo().Assembly.Location)) using (var peReader = new PEReader(stream)) { MetadataReader reader = peReader.GetMetadataReader(); var provider = new CustomAttributeTypeProvider(); TypeDefinitionHandle typeDefHandle = TestMetadataResolver.FindTestType(reader, typeof(HasAttributes)); int i = 0; foreach (CustomAttributeHandle attributeHandle in reader.GetCustomAttributes(typeDefHandle)) { CustomAttribute attribute = reader.GetCustomAttribute(attributeHandle); CustomAttributeValue <string> value = attribute.DecodeValue(provider); switch (i++) { case 0: Assert.Empty(value.FixedArguments); Assert.Empty(value.NamedArguments); break; case 1: Assert.Equal(3, value.FixedArguments.Length); Assert.Equal("string", value.FixedArguments[0].Type); Assert.Equal("0", value.FixedArguments[0].Value); Assert.Equal("int32", value.FixedArguments[1].Type); Assert.Equal(1, value.FixedArguments[1].Value); Assert.Equal("float64", value.FixedArguments[2].Type); Assert.Equal(2.0, value.FixedArguments[2].Value); Assert.Empty(value.NamedArguments); break; case 2: Assert.Equal(3, value.NamedArguments.Length); Assert.Equal(CustomAttributeNamedArgumentKind.Field, value.NamedArguments[0].Kind); Assert.Equal("StringField", value.NamedArguments[0].Name); Assert.Equal("string", value.NamedArguments[0].Type); Assert.Equal("0", value.NamedArguments[0].Value); Assert.Equal(CustomAttributeNamedArgumentKind.Field, value.NamedArguments[1].Kind); Assert.Equal("Int32Field", value.NamedArguments[1].Name); Assert.Equal("int32", value.NamedArguments[1].Type); Assert.Equal(1, value.NamedArguments[1].Value); Assert.Equal(CustomAttributeNamedArgumentKind.Property, value.NamedArguments[2].Kind); Assert.Equal("SByteEnumArrayProperty", value.NamedArguments[2].Name); Assert.Equal(typeof(SByteEnum).FullName + "[]", value.NamedArguments[2].Type); var array = (ImmutableArray <CustomAttributeTypedArgument <string> >)(value.NamedArguments[2].Value); Assert.Equal(1, array.Length); Assert.Equal(typeof(SByteEnum).FullName, array[0].Type); Assert.Equal((sbyte)SByteEnum.Value, array[0].Value); break; default: // TODO: https://github.com/dotnet/corefx/issues/6534 // The other cases are missing corresponding assertions. This needs some refactoring to // be data-driven. A better approach would probably be to generically compare reflection // CustomAttributeData to S.R.M CustomAttributeValue for every test attribute applied. break; } } } }