@ -429,6 +429,47 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -429,6 +429,47 @@ namespace ICSharpCode.Decompiler.CSharp
}
#endregion
#region NativeOrdering
/// <summary>
/// Determines whether a given type requires that its methods be ordered precisely as they were originally defined.
/// </summary>
/// <param name="typeDef">The type whose members may need native ordering.</param>
internal bool RequiresNativeOrdering ( ITypeDefinition typeDef )
{
// The main scenario for requiring the native method ordering is COM interop, where the V-table is fixed by the ABI
return ComHelper . IsComImport ( typeDef ) ;
}
/// <summary>
/// Compare handles with the method definition ordering intact by using the underlying method's MetadataToken,
/// which is defined as the index into a given metadata table. This should equate to the original order that
/// methods and properties were defined by the author.
/// </summary>
/// <param name="typeDef">The type whose members to order using their method's MetadataToken</param>
/// <returns>A sequence of all members ordered by MetadataToken</returns>
internal IEnumerable < IMember > GetMembersWithNativeOrdering ( ITypeDefinition typeDef )
{
EntityHandle GetOrderingHandle ( IMember member )
{
// Note! Technically COM interfaces could define property getters and setters out of order or interleaved with other
// methods, but C# doesn't support this so we can't define it that way.
if ( member is IMethod )
return member . MetadataToken ;
else if ( member is IProperty property )
return property . Getter ? . MetadataToken ? ? property . Setter ? . MetadataToken ? ? property . MetadataToken ;
else if ( member is IEvent @event )
return @event . AddAccessor ? . MetadataToken ? ? @event . RemoveAccessor ? . MetadataToken ? ? @event . InvokeAccessor ? . MetadataToken ? ? @event . MetadataToken ;
else
return member . MetadataToken ;
}
return typeDef . Fields . Concat < IMember > ( typeDef . Properties ) . Concat ( typeDef . Methods ) . Concat ( typeDef . Events ) . OrderBy ( ( member ) = > GetOrderingHandle ( member ) , HandleComparer . Default ) ;
}
#endregion
static PEFile LoadPEFile ( string fileName , DecompilerSettings settings )
{
settings . LoadInMemory = true ;
@ -1264,48 +1305,61 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -1264,48 +1305,61 @@ namespace ICSharpCode.Decompiler.CSharp
// With C# 9 records, the relative order of fields and properties matters:
IEnumerable < IMember > fieldsAndProperties = recordDecompiler ? . FieldsAndProperties
? ? typeDef . Fields . Concat < IMember > ( typeDef . Properties ) ;
foreach ( var fieldOrProperty in fieldsAndProperties )
// For COM interop scenarios, the relative order of virtual functions/properties matters:
IEnumerable < IMember > allOrderedMembers = RequiresNativeOrdering ( typeDef ) ? GetMembersWithNativeOrdering ( typeDef ) :
fieldsAndProperties . Concat < IMember > ( typeDef . Events ) . Concat < IMember > ( typeDef . Methods ) ;
foreach ( var member in allOrderedMembers )
{
if ( fieldOrProperty . MetadataToken . IsNil | | MemberIsHidden ( module . PEFile , fieldOrProperty . MetadataToken , settings ) )
{
continue ;
}
if ( fieldOrProperty is IField field )
if ( member is IField | | member is IProperty )
{
if ( typeDef . Kind = = TypeKind . Enum & & ! field . IsConst )
var fieldOrProperty = member ;
if ( fieldOrProperty . MetadataToken . IsNil | | MemberIsHidden ( module . PEFile , fieldOrProperty . MetadataToken , settings ) )
{
continue ;
var memberDecl = DoDecompile ( field , decompileRun , decompilationContext . WithCurrentMember ( field ) ) ;
typeDecl . Members . Add ( memberDecl ) ;
}
if ( fieldOrProperty is IField field )
{
if ( typeDef . Kind = = TypeKind . Enum & & ! field . IsConst )
continue ;
var memberDecl = DoDecompile ( field , decompileRun , decompilationContext . WithCurrentMember ( field ) ) ;
typeDecl . Members . Add ( memberDecl ) ;
}
else if ( fieldOrProperty is IProperty property )
{
if ( recordDecompiler ? . PropertyIsGenerated ( property ) = = true )
{
continue ;
}
var propDecl = DoDecompile ( property , decompileRun , decompilationContext . WithCurrentMember ( property ) ) ;
typeDecl . Members . Add ( propDecl ) ;
}
}
else if ( fieldOrProperty is IProperty property )
else if ( member is IMethod method )
{
if ( recordDecompiler ? . PropertyIsGenerated ( property ) = = true )
if ( recordDecompiler ? . MethodIsGenerated ( method ) = = true )
{
continue ;
}
var propDecl = DoDecompile ( property , decompileRun , decompilationContext . WithCurrentMember ( property ) ) ;
typeDecl . Members . Add ( propDecl ) ;
}
}
foreach ( var @event in typeDef . Events )
{
if ( ! @event . MetadataToken . IsNil & & ! MemberIsHidden ( module . PEFile , @event . MetadataToken , settings ) )
{
var eventDecl = DoDecompile ( @event , decompileRun , decompilationContext . WithCurrentMember ( @event ) ) ;
typeDecl . Members . Add ( eventDecl ) ;
if ( ! method . MetadataToken . IsNil & & ! MemberIsHidden ( module . PEFile , method . MetadataToken , settings ) )
{
var memberDecl = DoDecompile ( method , decompileRun , decompilationContext . WithCurrentMember ( method ) ) ;
typeDecl . Members . Add ( memberDecl ) ;
typeDecl . Members . AddRange ( AddInterfaceImplHelpers ( memberDecl , method , typeSystemAstBuilder ) ) ;
}
}
}
foreach ( var method in typeDef . Methods )
{
if ( recordDecompiler ? . MethodIsGenerated ( method ) = = true )
else if ( member is IEvent @event )
{
continue ;
if ( ! @event . MetadataToken . IsNil & & ! MemberIsHidden ( module . PEFile , @event . MetadataToken , settings ) )
{
var eventDecl = DoDecompile ( @event , decompileRun , decompilationContext . WithCurrentMember ( @event ) ) ;
typeDecl . Members . Add ( eventDecl ) ;
}
}
if ( ! method . MetadataToken . IsNil & & ! MemberIsHidden ( module . PEFile , method . MetadataToken , settings ) )
els e
{
var memberDecl = DoDecompile ( method , decompileRun , decompilationContext . WithCurrentMember ( method ) ) ;
typeDecl . Members . Add ( memberDecl ) ;
typeDecl . Members . AddRange ( AddInterfaceImplHelpers ( memberDecl , method , typeSystemAstBuilder ) ) ;
throw new ArgumentOutOfRangeException ( "Unexpected member type" ) ;
}
}
if ( typeDecl . Members . OfType < IndexerDeclaration > ( ) . Any ( idx = > idx . PrivateImplementationType . IsNull ) )