Repository: dotnet/runtime
File: src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderTests.cs (C#)

Code before:
                }
            }
        }

        [Fact]
        public void SaveInterfaceOverrideWithCustomModifier()
        {
            using (TempFile file = TempFile.Create())
            {
                AssemblyName name = new("TestAssembly");
                PersistedAssemblyBuilder assemblyBuilder = AssemblySaveTools.PopulateAssemblyBuilder(name);
                ModuleBuilder mb = assemblyBuilder.DefineDynamicModule("My Module");
                TypeBuilder tb = mb.DefineType("IMethodWithModifiersImpl", TypeAttributes.Class | TypeAttributes.Public);
                tb.AddInterfaceImplementation(typeof(IMethodWithModifiers));
                MethodInfo mRun = typeof(IMethodWithModifiers).GetMethod(nameof(IMethodWithModifiers.Run))!;
                MethodBuilder m = tb.DefineMethod("IMethodWithModifiers.Run",
                    MethodAttributes.Private | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual,
                    CallingConventions.Standard,
                    returnType: mRun.ReturnParameter.GetModifiedParameterType(),
                    returnTypeRequiredCustomModifiers: null,
                    returnTypeOptionalCustomModifiers: null,
                    parameterTypes: mRun.GetParameters().Select(x => x.GetModifiedParameterType()).ToArray(),
                    parameterTypeRequiredCustomModifiers: null,
                    parameterTypeOptionalCustomModifiers: null);
                // The method's parameter has a modreq; make sure it is added to the override's signature.
                // See https://github.com/dotnet/runtime/issues/123857
                tb.DefineMethodOverride(m, mRun);
                ParameterBuilder pb = m.DefineParameter(1, ParameterAttributes.In, "x");
                pb.SetCustomAttribute(new CustomAttributeBuilder(typeof(IsReadOnlyAttribute).GetConstructor(types: [])!, []));
                m.GetILGenerator().Emit(OpCodes.Ret);
                tb.CreateType();
                assemblyBuilder.Save(file.Path);

                TestAssemblyLoadContext context = new();
                // Load the assembly and check that loading the type does not throw.
                Assembly loadedAsm = context.LoadFromAssemblyPath(file.Path);
                _ = loadedAsm.GetType(tb.Name, throwOnError: true);
                context.Unload();
            }
        }

        [Fact]
        public void SaveMultipleGenericTypeParametersToEnsureSortingWorks()
        {
            using (TempFile file = TempFile.Create())
            {
                PersistedAssemblyBuilder assemblyBuilder = AssemblySaveTools.PopulateAssemblyBuilder(s_assemblyName);
                ModuleBuilder mb = assemblyBuilder.DefineDynamicModule("My Module");
                TypeBuilder tb = mb.DefineType("TestInterface1", TypeAttributes.Interface | TypeAttributes.Abstract);
                GenericTypeParameterBuilder[] typeParams = tb.DefineGenericParameters(["U", "T"]);
                typeParams[1].SetInterfaceConstraints([typeof(INoMethod), typeof(IOneMethod)]);

Review comment (suggestion):
```suggestion
```
The next line (DefineMethodOverride) is not making sure that the modreq is added to the override's signature. This comment is unnecessary or misplaced.

Code after:
                }
            }
        }

        [Fact]
        public void SaveInterfaceOverrideWithCustomModifier()
        {
            using (TempFile file = TempFile.Create())
            {
                AssemblyName name = new("TestAssembly");
                PersistedAssemblyBuilder assemblyBuilder = AssemblySaveTools.PopulateAssemblyBuilder(name);
                ModuleBuilder mb = assemblyBuilder.DefineDynamicModule("My Module");

                TypeBuilder tb = mb.DefineType("IMethodWithModifiersImpl", TypeAttributes.Class | TypeAttributes.Public);
                tb.AddInterfaceImplementation(typeof(IMethodWithModifiers));
                MethodInfo mRun = typeof(IMethodWithModifiers).GetMethod(nameof(IMethodWithModifiers.Run));
                MethodBuilder m = tb.DefineMethod("IMethodWithModifiers.Run",
                    MethodAttributes.Private | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual,
                    CallingConventions.Standard,
                    returnType: mRun.ReturnParameter.GetModifiedParameterType(),
                    returnTypeRequiredCustomModifiers: null,
                    returnTypeOptionalCustomModifiers: null,
                    // The first parameter will have modreqs specified from parameterTypeRequiredCustomModifiers, and the second from parameterTypes.
                    parameterTypes: mRun.GetParameters().Select((x, i) => i == 0 ? x.ParameterType : x.GetModifiedParameterType()).ToArray(),
                    parameterTypeRequiredCustomModifiers: [[typeof(InAttribute)], null],
                    parameterTypeOptionalCustomModifiers: null);
                tb.DefineMethodOverride(m, mRun);
                ParameterBuilder pb = m.DefineParameter(1, ParameterAttributes.In, "x");
                pb.SetCustomAttribute(new CustomAttributeBuilder(typeof(IsReadOnlyAttribute).GetConstructor(types: []), []));
                m.GetILGenerator().Emit(OpCodes.Ret);
                MethodInfo mRun2 = typeof(IMethodWithModifiers).GetMethod(nameof(IMethodWithModifiers.Run2));
                MethodBuilder m2 = tb.DefineMethod("IMethodWithModifiers.Run2",
                    MethodAttributes.Private | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual,
                    CallingConventions.Standard,
                    returnType: mRun2.ReturnParameter.GetModifiedParameterType(),
                    returnTypeRequiredCustomModifiers: null,
                    returnTypeOptionalCustomModifiers: null,
                    parameterTypes: mRun2.GetParameters().Select(x => x.GetModifiedParameterType()).ToArray(),
                    // Test that passing null gets modreqs from the parameter types.
                    parameterTypeRequiredCustomModifiers: null,
                    parameterTypeOptionalCustomModifiers: null);
                tb.DefineMethodOverride(m2, mRun2);
                ParameterBuilder pb2 = m2.DefineParameter(1, ParameterAttributes.In, "x");
                pb2.SetCustomAttribute(new CustomAttributeBuilder(typeof(IsReadOnlyAttribute).GetConstructor(types: []), []));
                m2.GetILGenerator().Emit(OpCodes.Ret);

                tb.CreateType();
                assemblyBuilder.Save(file.Path);

                TestAssemblyLoadContext context = new();
                // Load the assembly and check that loading the type does not throw.