Skip to content

Arguments to Custom Attributes Do Not Update Upon Type Rename  #576

@djhohnstein

Description

@djhohnstein

AsmResolver Version

4.11.2

.NET Version

.NET 6.0

Operating System

Windows

Describe the Bug

Class types that use a custom attribute type decorator do not update the class type's custom attribute's fixed arguments to reflect the attribute type's new name upon renaming.

This can be explained better with code. Let's suppose we have two type definitions (TypeDefinition) for classes ClassA and ClassB. ClassB has an attribute decorator of MyCustomAttribute which takes one argument, a type. ClassB is instantiated as follows:

[MyCustomAttribute(typeof(ClassA))]
public class ClassB {
    ....
}

Let's say the TypeDefinition variable for ClassA is stored as a variable as follows:

TypeDefinition tDefForClassA = Module.GetAllTypes().Where(x => string.Equals(x.Name?.Value, "ClassA"));

If I were to rename ClassA via:

tDefForAttr.tDefForClassA = "ClassC"

You would see that the arguments for the CustomAttributes field on ClassB's TypeDefinition object does not update to reflect the new argument of ClassC.

How To Reproduce

Create an example project with the following file:

using System;

namespace TestProject
{
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    class MyCustomAttribute : Attribute
    {
        public Type Type { get; set; }

        public MyCustomAttribute(Type outputType)
        {
            Type = outputType;
        }
    }

    internal class ClassA
    {
        
    }

    [MyCustomAttribute(typeof(ClassA))]
    internal class ClassB
    {
        internal void HelloWorld()
        {
            Console.WriteLine("Hello, world!");
        }
    }
    
    internal class Program
    {
        
        public static void Main(string[] args)
        {
            var b = new ClassB();
            b.HelloWorld();
        }
    }
}

Compile to TestProject.exe. Then, in a separate project leveraging AsmResolver, use the following code to update the ClassA type definition name:

var module = ModuleDefinition.FromFile("TestProject.exe");
TypeDefinition tDefClassA = module.GetAllTypes().First(x => x.Name == "ClassA");
tDefClassA.Name = "ClassC";
_editor.Module.Write("SecondTest.exe");

If you were to inspect ClassB's type definition via:

TypeDefinition tDefClassB = module.GetAllTypes().First(x => x.Name == "ClassB");
// Inspect tDefClassB.CustomAttributes.Signature

You would see that the signature here still references ClassA which no longer exists in the assembly.

Expected Behavior

The arguments to custom attribute decorator of classes getting updated as required. For example, ClassC should now populate the arguments of the signature in the previous code instead of ClassA.

Actual Behavior

ClassA remains referenced as an argument to the attribute constructor even though this type no longer exists.

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugdotnetIssues related to AsmResolver.DotNet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions