-
Notifications
You must be signed in to change notification settings - Fork 128
Use enum for method parameter indexing #2993
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
Conversation
vitek-karas
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't look at the details, but I like the approach of using C# type system to differentiate the two cases - really nice idea!
| } | ||
| } | ||
|
|
||
| public static SourceParameterIndex GetSourceParameter (MethodDefinition method, Instruction operation) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| public static SourceParameterIndex GetSourceParameter (MethodDefinition method, Instruction operation) | |
| public static SourceParameterIndex GetSourceParameterIndex (MethodDefinition method, Instruction operation) |
| /// <summary> | ||
| /// Represents the index of arguments passed to a function in IL. Generally prefer to use <see cref="ILLink.Shared.SourceParameterIndex"/> when possible. See also <seealso cref="Mono.Linker.ParameterHelpers"/>. | ||
| /// </summary> | ||
| /// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a comment describing that you're using enums as a way to separate source/IL indexes in the C# type system (took me a while to figure that out), and that they're actually used as numbers (relying on the fact that enum is really just an Int32).
Would also be nice to describe the numbering scheme here (IL parameter indexes are >=0 and for "instance" call the 0 is this and others are +1 .... and then something similar for source indexes).
| { | ||
| /// <summary> | ||
| /// Used to indicate the index of the parameter in source code (i.e. the same regardless of if there is a `this` or not) | ||
| /// </summary> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as for ILParameterIndex
| /// <summary> | ||
| /// Used to indicate the index of the parameter in source code (i.e. the same regardless of if there is a `this` or not) | ||
| /// </summary> | ||
| public enum SourceParameterIndex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find the naming a bit weird - it's not exactly clear what "source" means here. That said - I didn't come up with a better name really. So I guess we should just add a good comment (maybe add couple of examples).
sbomer
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it, thank you!
|
|
||
| bool isByRef; | ||
|
|
||
| // Thank you Cecil, Operand being a ParameterDefinition instead of an integer, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment can move to ILParameterIndexFromInstruction 🤣
| paramNum = paramDefinition.Index; | ||
| } | ||
|
|
||
| // This is semantically wrong if it returns true - we would representing a reference parameter as a reference to a parameter - but it should be fine for now |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is still true right? Please keep it in the new code below.
|
Sorry for the force push, I ran into issues with rebasing and it seemed like the cleanest option. I've updated the description to describe the updated code. This version differentiates SourceParameterIndex and |
tlakollo
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only nit stuff from my review
| public static ILParameterIndex ILParameterIndexFromSourceParameterIndex (MethodReference method, SourceParameterIndex sourceIndex) | ||
| { | ||
| if (method.HasImplicitThis ()) | ||
| return (ILParameterIndex) ((int)sourceIndex + 1); | ||
|
|
||
| return (ILParameterIndex) (int)sourceIndex; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: maybe we can simplify it to
| public static ILParameterIndex ILParameterIndexFromSourceParameterIndex (MethodReference method, SourceParameterIndex sourceIndex) | |
| { | |
| if (method.HasImplicitThis ()) | |
| return (ILParameterIndex) ((int)sourceIndex + 1); | |
| return (ILParameterIndex) (int)sourceIndex; | |
| } | |
| public static ILParameterIndex ILParameterIndexFromSourceParameterIndex (MethodReference method, SourceParameterIndex sourceIndex) => | |
| method.HasImplicitThis () ? (ILParameterIndex) ((int)sourceIndex + 1) : (ILParameterIndex) (int)sourceIndex; |
| /// Represents the index of arguments passed to a function in IL (i.e. (ILParameterIndexs)0 represents `this` for non-static methods. | ||
| /// This is used to enforce a differentiatiation between scenarios where the 0 index should be `this` and when the 0 index should be the first non-this parameter in the type system. | ||
| /// There are no named enum values, the underlying integer value represents the index value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| /// Represents the index of arguments passed to a function in IL (i.e. (ILParameterIndexs)0 represents `this` for non-static methods. | |
| /// This is used to enforce a differentiatiation between scenarios where the 0 index should be `this` and when the 0 index should be the first non-this parameter in the type system. | |
| /// There are no named enum values, the underlying integer value represents the index value. | |
| /// Represents the index of arguments passed to a function in IL (i.e. (ILParameterIndex)0 represents `this` for non-static methods. | |
| /// This is used to enforce a differentiation between scenarios where the 0 index should be `this` and when the 0 index should be the first non-this parameter in the type system. | |
| /// There are no named enum values, the underlying integer value represents the index value. |
| P:Mono.Collections.Generic.Collection`1{Mono.Cecil.ParameterDefinition}.Item(System.Int32); use x | ||
| P:Mono.Cecil.ParameterDefinitionCollection.Item(System.Int32); use x |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's this BannedSymbols file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I was looking into using the BannedApiAnalyzer to prevent indexing MethodReference.Parameters directly with an int, but I couldn't get it to work. These changes shouldn't be there.
| /// This enum and <see cref="T:Mono.Linker.ILParameterIndex"/> is used to enforce a differentiatiation between scenarios where the 0 index should be `this` and when the 0 index should be the first non-this parameter in the type system. | ||
| /// `this` is the only named enum value. For all others, the underlying integer value represents the index value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| /// This enum and <see cref="T:Mono.Linker.ILParameterIndex"/> is used to enforce a differentiatiation between scenarios where the 0 index should be `this` and when the 0 index should be the first non-this parameter in the type system. | |
| /// `this` is the only named enum value. For all others, the underlying integer value represents the index value. | |
| /// This enum and <see cref="T:Mono.Linker.ILParameterIndex"/> is used to enforce a differentiation between scenarios where the 0 index should be `this` and when the 0 index should be the first non-this parameter in the type system. | |
| /// `this` is the only named enum value. For all others, the underlying integer value represents the index value. |
| /// <example> | ||
| /// 0 is the first argument passed to the function in C#, | ||
| /// 1 is the next, and so on. These can be used to index parameters. | ||
| /// -1 is a flag to indicate the `this` parameter, and when SourceParamater |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: this comment ends abruptly in my view
| /// -1 is a flag to indicate the `this` parameter, and when SourceParamater | |
| /// -1 is a flag to indicate the `this` parameter, and when SourceParameter |
This reverts commit 45e2e59.
This change adds ILParameterIndex to represent the IL-based indexing where 0 may refer to this, and SourceParameterIndex where 0 is the first "real" parameter in C# source code. Converting from ILParameterIndex to SourceParameterIndex returns a SourceParameterKind to differentiate between thisand other parameters and ensure that anySourceParameterIndexwill be able to indexMethodReference.Parameters`. It uses these in ParameterReferenceValue as well as GetMethodParameterValue() and adds a GetMethodThisParameterValue(), ThisParameterReferenceValue, and bubbles the changes where necessary. Most places should use SourceParameterIndex, and convert to ILParameterIndex when necessary or at the boundary of updated and old code. Commit migrated from dotnet/linker@45e2e59
I've run into multiple issues when I think an
int parameterIndexis the source-based index when it is the IL-based index (offset by 1 forthis) or vice versa.In order to fix this, we can use different enums for each definition of "Parameter Index" to enforce the correct usage and avoid the off by one errors. The enums rely on the underlying
intvalue to provide the index number.This change adds
ILParameterIndexto represent the IL-based indexing where 0 may refer tothis, and SourceParameterIndex where 0 is the first "real" parameter in C# source code. Converting from ILParameterIndex to SourceParameterIndex returns a SourceParameterKind to differentiate betweenthisand other parameters and ensure that anySourceParameterIndexwill be able to indexMethodReference.Parameters`.It uses these in
ParameterReferenceValueas well asGetMethodParameterValue()and adds aGetMethodThisParameterValue(),ThisParameterReferenceValue, and bubbles the changes where necessary.Most places should use SourceParameterIndex, and convert to ILParameterIndex when necessary or at the boundary of updated and old code.
I'll continue to update the code to use these enums in other PRs.