Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Under what circumstances can System.Reflection.ParameterInfo.Name be null? #73188

Closed
eiriktsarpalis opened this issue Aug 1, 2022 · 7 comments
Labels
area-System.Reflection question Answer questions and provide assistance, not an issue with source code or documentation.

Comments

@eiriktsarpalis
Copy link
Member

Consider the following console app:

using System;
using System.Reflection;

Type type = Assembly.GetExecutingAssembly().GetType("System.Runtime.CompilerServices.NullableContextAttribute")!;
ParameterInfo parameterInfo = type.GetConstructor(new Type[] { typeof(byte) })!.GetParameters()[0];
Console.WriteLine(parameterInfo.Name is not null); // Expected "P_0", got null

// Force generation of a NullableContextAttribute in this assembly
static string? MethodWithNullableAnnotations() => throw new NotImplementedException();

// Generated attribute:
//
//[CompilerGenerated]
//[Microsoft.CodeAnalysis.Embedded]
//[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
//internal sealed class NullableContextAttribute : Attribute
//{
//    public readonly byte Flag;

//    public NullableContextAttribute(byte P_0)
//    {
//        Flag = P_0;
//    }
//}

I'm not sure if this is a bug or not, but I would have expected parameterInfo.Name to be non-null in this case. The issue does not reproduce if I manually define the attribute as decompiled. Documentation for ParameterInfo.Name seems to suggest that Name can be null if the parameter is obtained via MethodInfo.ReturnParameter but this is not the case in this reproduction. Can reproduce the same behavior in both .NET 7 and netfx runtimes.

Discovered while investigating #58690.

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Aug 1, 2022
@ghost
Copy link

ghost commented Aug 1, 2022

Tagging subscribers to this area: @dotnet/area-system-reflection
See info in area-owners.md if you want to be subscribed.

Issue Details

Consider the following console app:

using System;
using System.Reflection;

Type type = Assembly.GetExecutingAssembly().GetType("System.Runtime.CompilerServices.NullableContextAttribute")!;
ParameterInfo parameterInfo = type.GetConstructor(new Type[] { typeof(byte) })!.GetParameters()[0];
Console.WriteLine(parameterInfo.Name is not null); // Expected "P_0", got null

// Force generation of a NullableContextAttribute in this assembly
static string? MethodWithNullableAnnotations() => throw new NotImplementedException();

// Generated attribute:
//
//[CompilerGenerated]
//[Microsoft.CodeAnalysis.Embedded]
//[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
//internal sealed class NullableContextAttribute : Attribute
//{
//    public readonly byte Flag;

//    public NullableContextAttribute(byte P_0)
//    {
//        Flag = P_0;
//    }
//}

I'm not sure if this is a bug or not, but I would have expected parameterInfo.Name to be non-null in this case. The issue does not reproduce if I manually define the attribute as decompiled. Documentation for ParameterInfo.Name seems to suggest that Name can be null if the parameter is obtained via MethodInfo.ReturnParameter but this is not the case in this reproduction. Can reproduce the same behavior in both .NET 7 and netfx runtimes.

Discovered while investigating #58690.

Author: eiriktsarpalis
Assignees: -
Labels:

area-System.Reflection

Milestone: -

@stephentoub
Copy link
Member

stephentoub commented Aug 1, 2022

Documentation for ParameterInfo.Name seems to suggest that Name can be null if the parameter is obtained via MethodInfo.ReturnParameter but this is not the case in this reproduction

This prints "True":

public class Program
{
    private static void Main() =>
        Console.WriteLine(typeof(Program).GetMethod("M")!.ReturnParameter.Name is null);

    public static object M() => new object();
}

(The title of this issue is about PropertyInfo, but the contents is about ParameterInfo... I assume you meant the latter)

@stephentoub
Copy link
Member

Oh, I misunderstood your question. You're not asking whether there are any situations where it can be null and arguing it can't, you're asking why it's null in the specific situation in your repro?

@eiriktsarpalis eiriktsarpalis changed the title Under what circumstances can System.Reflection.PropertyInfo.Name be null? Under what circumstances can System.Reflection.ParameterInfo.Name be null? Aug 1, 2022
@eiriktsarpalis
Copy link
Member Author

you're asking why it's null in the specific situation in your repro?

Correct.

@stephentoub
Copy link
Member

stephentoub commented Aug 1, 2022

Parameter names are optional in IL. In the case in your repro, I expect Roslyn doesn't emit one for the NullableContextAttribute's ctor parameter it synthesizes. Our own linker will even strip parameter names in some builds in order to reduce size.

@stephentoub
Copy link
Member

Expected "P_0", got null

This expected "P_0" because that's what ILSpy renders? I believe this is just ILSpy trying to create valid C# and manufacturing a parameter name when one doesn't exist, e.g.
https://github.com/icsharpcode/ILSpy/blob/2ed9ad6b51110acfa5430a50f34b985c9c4eb1ac/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs#L1243-L1255

@eiriktsarpalis
Copy link
Member Author

Gotcha. It would seem that P_0 is just a placeholder name inserted by the decompiler. This is what the IL shows

	.method public hidebysig specialname rtspecialname 
		instance void .ctor (
			uint8 ''
		) cil managed 
	{
		// Method begins at RVA 0x2082
		// Header size: 1
		// Code size: 15 (0xf)
		.maxstack 8

		IL_0000: ldarg.0
		IL_0001: call instance void [System.Runtime]System.Attribute::.ctor()
		IL_0006: nop
		IL_0007: ldarg.0
		IL_0008: ldarg.1
		IL_0009: stfld uint8 System.Runtime.CompilerServices.NullableContextAttribute::Flag
		IL_000e: ret
	} // end of method NullableContextAttribute::.ctor

@ghost ghost removed the untriaged New issue has not been triaged by the area owner label Aug 1, 2022
@eiriktsarpalis eiriktsarpalis added question Answer questions and provide assistance, not an issue with source code or documentation. untriaged New issue has not been triaged by the area owner and removed untriaged New issue has not been triaged by the area owner labels Aug 1, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Sep 1, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Reflection question Answer questions and provide assistance, not an issue with source code or documentation.
Projects
None yet
Development

No branches or pull requests

2 participants