@@ -318,7 +318,9 @@ public static bool MemberIsHidden(MetadataFile module, EntityHandle member, Deco
318318 return true ;
319319 if ( settings . FixedBuffers && name . StartsWith ( "<" , StringComparison . Ordinal ) && name . Contains ( "__FixedBuffer" ) )
320320 return true ;
321- if ( settings . InlineArrays && name . StartsWith ( "<>y__InlineArray" , StringComparison . Ordinal ) && name . EndsWith ( "`1" ) )
321+ if ( settings . InlineArrays && name . StartsWith ( "<>y__InlineArray" , StringComparison . Ordinal ) && name . EndsWith ( "`1" , StringComparison . Ordinal ) )
322+ return true ;
323+ if ( settings . ExtensionMembers && name . StartsWith ( "<>E__" , StringComparison . Ordinal ) )
322324 return true ;
323325 }
324326 else if ( type . IsCompilerGenerated ( metadata ) )
@@ -1037,7 +1039,7 @@ public SyntaxTree Decompile(IEnumerable<EntityHandle> definitions)
10371039 break ;
10381040 case HandleKind . MethodDefinition :
10391041 IMethod method = module . GetDefinition ( ( MethodDefinitionHandle ) entity ) ;
1040- syntaxTree . Members . Add ( DoDecompile ( method , decompileRun , new SimpleTypeResolveContext ( method ) ) ) ;
1042+ syntaxTree . Members . Add ( DoDecompile ( method , decompileRun , new SimpleTypeResolveContext ( method ) , null ) ) ;
10411043 if ( first )
10421044 {
10431045 parentTypeDef = method . DeclaringTypeDefinition ;
@@ -1054,7 +1056,7 @@ public SyntaxTree Decompile(IEnumerable<EntityHandle> definitions)
10541056 break ;
10551057 case HandleKind . PropertyDefinition :
10561058 IProperty property = module . GetDefinition ( ( PropertyDefinitionHandle ) entity ) ;
1057- syntaxTree . Members . Add ( DoDecompile ( property , decompileRun , new SimpleTypeResolveContext ( property ) ) ) ;
1059+ syntaxTree . Members . Add ( DoDecompile ( property , decompileRun , new SimpleTypeResolveContext ( property ) , null ) ) ;
10581060 if ( first )
10591061 {
10601062 parentTypeDef = property . DeclaringTypeDefinition ;
@@ -1361,14 +1363,45 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun
13611363 partialTypeInfo = null ;
13621364 }
13631365
1366+ if ( settings . ExtensionMembers )
1367+ {
1368+ foreach ( var group in typeDef . ExtensionInfo ? . GetGroups ( ) ?? [ ] )
1369+ {
1370+ var ext = new ExtensionDeclaration ( ) ;
1371+ ext . TypeParameters . AddRange ( group . Key . DeclaringTypeDefinition . TypeParameters . Select ( tp => typeSystemAstBuilder . ConvertTypeParameter ( tp ) ) ) ;
1372+ ext . ReceiverParameters . Add ( typeSystemAstBuilder . ConvertParameter ( group . Key . Parameters . Single ( ) ) ) ;
1373+ AddAnnotationsToDeclaration ( method , ext , function , parameterOffset ) ;
1374+ ext . Constraints . AddRange ( group . Key . DeclaringTypeDefinition . TypeParameters . Select ( c => typeSystemAstBuilder . ConvertTypeParameterConstraint ( c ) ) ) ;
1375+
1376+ foreach ( var member in group )
1377+ {
1378+ IMember extMember = member . ExtensionMember ;
1379+ if ( member . ExtensionMember . IsAccessor )
1380+ {
1381+ extMember = member . ExtensionMember . AccessorOwner ;
1382+ }
1383+ if ( entityMap . Contains ( extMember ) || extMember . MetadataToken . IsNil )
1384+ {
1385+ // Member is already decompiled.
1386+ continue ;
1387+ }
1388+ EntityDeclaration extMemberDecl = DoDecompileExtensionMember ( extMember , typeDef . ExtensionInfo , decompileRun , decompilationContext ) ;
1389+ ext . Members . Add ( extMemberDecl ) ;
1390+ entityMap . Add ( extMember , extMemberDecl ) ;
1391+ }
1392+
1393+ typeDecl . Members . Add ( ext ) ;
1394+ }
1395+ }
1396+
13641397 // Decompile members that are not compiler-generated.
13651398 foreach ( var entity in allOrderedEntities )
13661399 {
13671400 if ( entity . MetadataToken . IsNil || MemberIsHidden ( module . MetadataFile , entity . MetadataToken , settings ) )
13681401 {
13691402 continue ;
13701403 }
1371- DoDecompileMember ( entity , recordDecompiler , partialTypeInfo ) ;
1404+ DoDecompileMember ( entity , recordDecompiler , partialTypeInfo , typeDef . ExtensionInfo ) ;
13721405 }
13731406
13741407 // Decompile compiler-generated members that are still needed.
@@ -1380,7 +1413,7 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun
13801413 // Member is already decompiled.
13811414 continue ;
13821415 }
1383- DoDecompileMember ( entity , recordDecompiler , partialTypeInfo ) ;
1416+ DoDecompileMember ( entity , recordDecompiler , partialTypeInfo , typeDef . ExtensionInfo ) ;
13841417 }
13851418
13861419 // Add all decompiled members to syntax tree in the correct order.
@@ -1470,13 +1503,18 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun
14701503 Instrumentation . DecompilerEventSource . Log . DoDecompileTypeDefinition ( typeDef . FullName , watch . ElapsedMilliseconds ) ;
14711504 }
14721505
1473- void DoDecompileMember ( IEntity entity , RecordDecompiler recordDecompiler , PartialTypeInfo partialType )
1506+ void DoDecompileMember ( IEntity entity , RecordDecompiler recordDecompiler , PartialTypeInfo partialType , ExtensionInfo extensionInfo )
14741507 {
14751508 if ( partialType != null && partialType . IsDeclaredMember ( entity . MetadataToken ) )
14761509 {
14771510 return ;
14781511 }
14791512
1513+ if ( settings . ExtensionMembers && extensionInfo != null && entity is IMethod m && extensionInfo . InfoOfImplementationMember ( m ) . HasValue )
1514+ {
1515+ return ;
1516+ }
1517+
14801518 EntityDeclaration entityDecl ;
14811519 switch ( entity )
14821520 {
@@ -1497,15 +1535,15 @@ void DoDecompileMember(IEntity entity, RecordDecompiler recordDecompiler, Partia
14971535 {
14981536 return ;
14991537 }
1500- entityDecl = DoDecompile ( property , decompileRun , decompilationContext . WithCurrentMember ( property ) ) ;
1538+ entityDecl = DoDecompile ( property , decompileRun , decompilationContext . WithCurrentMember ( property ) , null ) ;
15011539 entityMap . Add ( property , entityDecl ) ;
15021540 break ;
15031541 case IMethod method :
15041542 if ( recordDecompiler ? . MethodIsGenerated ( method ) == true )
15051543 {
15061544 return ;
15071545 }
1508- entityDecl = DoDecompile ( method , decompileRun , decompilationContext . WithCurrentMember ( method ) ) ;
1546+ entityDecl = DoDecompile ( method , decompileRun , decompilationContext . WithCurrentMember ( method ) , null ) ;
15091547 entityMap . Add ( method , entityDecl ) ;
15101548 foreach ( var helper in AddInterfaceImplHelpers ( entityDecl , method , typeSystemAstBuilder ) )
15111549 {
@@ -1543,6 +1581,19 @@ void DoDecompileMember(IEntity entity, RecordDecompiler recordDecompiler, Partia
15431581 }
15441582 }
15451583
1584+ private EntityDeclaration DoDecompileExtensionMember ( IMember extMember , ExtensionInfo info , DecompileRun decompileRun , ITypeResolveContext decompilationContext )
1585+ {
1586+ switch ( extMember )
1587+ {
1588+ case IProperty p :
1589+ return DoDecompile ( p , decompileRun , decompilationContext . WithCurrentMember ( p ) , info ) ;
1590+ case IMethod m :
1591+ return DoDecompile ( m , decompileRun , decompilationContext . WithCurrentMember ( m ) , info ) ;
1592+ }
1593+
1594+ throw new NotSupportedException ( $ "Extension member { extMember } is not supported for decompilation.") ;
1595+ }
1596+
15461597 EnumValueDisplayMode DetectBestEnumValueDisplayMode ( ITypeDefinition typeDef , MetadataFile module )
15471598 {
15481599 if ( typeDef . HasAttribute ( KnownAttribute . Flags ) )
@@ -1604,7 +1655,7 @@ EnumValueDisplayMode DetectBestEnumValueDisplayMode(ITypeDefinition typeDef, Met
16041655 return firstValue == 0 ? EnumValueDisplayMode . None : EnumValueDisplayMode . FirstOnly ;
16051656 }
16061657
1607- EntityDeclaration DoDecompile ( IMethod method , DecompileRun decompileRun , ITypeResolveContext decompilationContext )
1658+ EntityDeclaration DoDecompile ( IMethod method , DecompileRun decompileRun , ITypeResolveContext decompilationContext , ExtensionInfo extensionInfo )
16081659 {
16091660 Debug . Assert ( decompilationContext . CurrentMember == method ) ;
16101661 var watch = System . Diagnostics . Stopwatch . StartNew ( ) ;
@@ -1630,7 +1681,7 @@ EntityDeclaration DoDecompile(IMethod method, DecompileRun decompileRun, ITypeRe
16301681 }
16311682 if ( methodDefinition . HasBody ( ) )
16321683 {
1633- DecompileBody ( method , methodDecl , decompileRun , decompilationContext ) ;
1684+ DecompileBody ( method , methodDecl , decompileRun , decompilationContext , extensionInfo ) ;
16341685 }
16351686 else if ( ! method . IsAbstract && method . DeclaringType . Kind != TypeKind . Interface )
16361687 {
@@ -1699,7 +1750,7 @@ internal static bool IsWindowsFormsInitializeComponentMethod(IMethod method)
16991750 return method . ReturnType . Kind == TypeKind . Void && method . Name == "InitializeComponent" && method . DeclaringTypeDefinition . GetNonInterfaceBaseTypes ( ) . Any ( t => t . FullName == "System.Windows.Forms.Control" ) ;
17001751 }
17011752
1702- void DecompileBody ( IMethod method , EntityDeclaration entityDecl , DecompileRun decompileRun , ITypeResolveContext decompilationContext )
1753+ void DecompileBody ( IMethod method , EntityDeclaration entityDecl , DecompileRun decompileRun , ITypeResolveContext decompilationContext , ExtensionInfo extensionInfo )
17031754 {
17041755 try
17051756 {
@@ -1708,6 +1759,14 @@ void DecompileBody(IMethod method, EntityDeclaration entityDecl, DecompileRun de
17081759 UseRefLocalsForAccurateOrderOfEvaluation = settings . UseRefLocalsForAccurateOrderOfEvaluation ,
17091760 DebugInfo = DebugInfoProvider
17101761 } ;
1762+ int parameterOffset = 0 ;
1763+ if ( extensionInfo != null )
1764+ {
1765+ if ( ! method . IsStatic )
1766+ parameterOffset = 1 ; // implementation method has an additional receiver parameter
1767+ method = extensionInfo . InfoOfExtensionMember ( method ) . Value . ImplementationMethod ;
1768+ }
1769+
17111770 var methodDef = metadata . GetMethodDefinition ( ( MethodDefinitionHandle ) method . MetadataToken ) ;
17121771 var body = BlockStatement . Null ;
17131772 MethodBodyBlock methodBody ;
@@ -1727,7 +1786,7 @@ void DecompileBody(IMethod method, EntityDeclaration entityDecl, DecompileRun de
17271786 var function = ilReader . ReadIL ( ( MethodDefinitionHandle ) method . MetadataToken , methodBody , cancellationToken : CancellationToken ) ;
17281787 function . CheckInvariant ( ILPhase . Normal ) ;
17291788
1730- AddAnnotationsToDeclaration ( method , entityDecl , function ) ;
1789+ AddAnnotationsToDeclaration ( method , entityDecl , function , parameterOffset ) ;
17311790
17321791 var localSettings = settings . Clone ( ) ;
17331792 if ( IsWindowsFormsInitializeComponentMethod ( method ) )
@@ -1786,9 +1845,9 @@ void DecompileBody(IMethod method, EntityDeclaration entityDecl, DecompileRun de
17861845 }
17871846 }
17881847
1789- internal static void AddAnnotationsToDeclaration ( IMethod method , EntityDeclaration entityDecl , ILFunction function )
1848+ internal static void AddAnnotationsToDeclaration ( IMethod method , EntityDeclaration entityDecl , ILFunction function , int parameterOffset = 0 )
17901849 {
1791- int i = 0 ;
1850+ int i = parameterOffset ;
17921851 var parameters = function . Variables . Where ( v => v . Kind == VariableKind . Parameter ) . ToDictionary ( v => v . Index ) ;
17931852 foreach ( var parameter in entityDecl . GetChildrenByRole ( Roles . Parameter ) )
17941853 {
@@ -2023,7 +2082,7 @@ internal static bool IsFixedField(IField field, out IType type, out int elementC
20232082 return false ;
20242083 }
20252084
2026- EntityDeclaration DoDecompile ( IProperty property , DecompileRun decompileRun , ITypeResolveContext decompilationContext )
2085+ EntityDeclaration DoDecompile ( IProperty property , DecompileRun decompileRun , ITypeResolveContext decompilationContext , ExtensionInfo extensionInfo )
20272086 {
20282087 Debug . Assert ( decompilationContext . CurrentMember == property ) ;
20292088 var watch = System . Diagnostics . Stopwatch . StartNew ( ) ;
@@ -2053,11 +2112,11 @@ EntityDeclaration DoDecompile(IProperty property, DecompileRun decompileRun, ITy
20532112 bool setterHasBody = property . CanSet && property . Setter . HasBody ;
20542113 if ( getterHasBody )
20552114 {
2056- DecompileBody ( property . Getter , getter , decompileRun , decompilationContext ) ;
2115+ DecompileBody ( property . Getter , getter , decompileRun , decompilationContext , extensionInfo ) ;
20572116 }
20582117 if ( setterHasBody )
20592118 {
2060- DecompileBody ( property . Setter , setter , decompileRun , decompilationContext ) ;
2119+ DecompileBody ( property . Setter , setter , decompileRun , decompilationContext , extensionInfo ) ;
20612120 }
20622121 if ( ! getterHasBody && ! setterHasBody && ! property . IsAbstract && property . DeclaringType . Kind != TypeKind . Interface )
20632122 {
@@ -2113,11 +2172,11 @@ EntityDeclaration DoDecompile(IEvent ev, DecompileRun decompileRun, ITypeResolve
21132172 }
21142173 if ( adderHasBody )
21152174 {
2116- DecompileBody ( ev . AddAccessor , ( ( CustomEventDeclaration ) eventDecl ) . AddAccessor , decompileRun , decompilationContext ) ;
2175+ DecompileBody ( ev . AddAccessor , ( ( CustomEventDeclaration ) eventDecl ) . AddAccessor , decompileRun , decompilationContext , null ) ;
21172176 }
21182177 if ( removerHasBody )
21192178 {
2120- DecompileBody ( ev . RemoveAccessor , ( ( CustomEventDeclaration ) eventDecl ) . RemoveAccessor , decompileRun , decompilationContext ) ;
2179+ DecompileBody ( ev . RemoveAccessor , ( ( CustomEventDeclaration ) eventDecl ) . RemoveAccessor , decompileRun , decompilationContext , null ) ;
21212180 }
21222181 if ( ! adderHasBody && ! removerHasBody && ! ev . IsAbstract && ev . DeclaringType . Kind != TypeKind . Interface )
21232182 {
0 commit comments