Skip to content

Commit e5a8542

Browse files
Fix #3457: NRE when creating Mermaid diagram of assembly with (possibly) missing references.
1 parent 50e62ac commit e5a8542

File tree

2 files changed

+55
-21
lines changed

2 files changed

+55
-21
lines changed

ICSharpCode.Decompiler/TypeSystem/InheritanceHelper.cs

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
using System.Collections.Generic;
2121
using System.Linq;
2222

23+
#nullable enable
24+
2325
namespace ICSharpCode.Decompiler.TypeSystem
2426
{
2527
/// <summary>
@@ -34,7 +36,7 @@ public static class InheritanceHelper
3436
/// <summary>
3537
/// Gets the base member that has the same signature.
3638
/// </summary>
37-
public static IMember GetBaseMember(IMember member)
39+
public static IMember? GetBaseMember(IMember member)
3840
{
3941
return GetBaseMembers(member, false).FirstOrDefault();
4042
}
@@ -109,7 +111,7 @@ public static IEnumerable<IMember> GetBaseMembers(IMember member, bool includeIm
109111
/// <summary>
110112
/// Finds the member declared in 'derivedType' that has the same signature (could override) 'baseMember'.
111113
/// </summary>
112-
public static IMember GetDerivedMember(IMember baseMember, ITypeDefinition derivedType)
114+
public static IMember? GetDerivedMember(IMember baseMember, ITypeDefinition derivedType)
113115
{
114116
if (baseMember == null)
115117
throw new ArgumentNullException(nameof(baseMember));
@@ -120,9 +122,8 @@ public static IMember GetDerivedMember(IMember baseMember, ITypeDefinition deriv
120122
throw new ArgumentException("baseMember and derivedType must be from the same compilation");
121123

122124
baseMember = baseMember.MemberDefinition;
123-
bool includeInterfaces = baseMember.DeclaringTypeDefinition.Kind == TypeKind.Interface;
124-
IMethod method = baseMember as IMethod;
125-
if (method != null)
125+
bool includeInterfaces = baseMember.DeclaringTypeDefinition?.Kind == TypeKind.Interface;
126+
if (baseMember is IMethod method)
126127
{
127128
foreach (IMethod derivedMethod in derivedType.Methods)
128129
{
@@ -137,8 +138,7 @@ public static IMember GetDerivedMember(IMember baseMember, ITypeDefinition deriv
137138
}
138139
}
139140
}
140-
IProperty property = baseMember as IProperty;
141-
if (property != null)
141+
if (baseMember is IProperty property)
142142
{
143143
foreach (IProperty derivedProperty in derivedType.Properties)
144144
{
@@ -175,7 +175,7 @@ internal static IEnumerable<IAttribute> GetAttributes(ITypeDefinition typeDef)
175175
{
176176
foreach (var baseType in typeDef.GetNonInterfaceBaseTypes().Reverse())
177177
{
178-
ITypeDefinition baseTypeDef = baseType.GetDefinition();
178+
ITypeDefinition? baseTypeDef = baseType.GetDefinition();
179179
if (baseTypeDef == null)
180180
continue;
181181
foreach (var attr in baseTypeDef.GetAttributes())
@@ -185,11 +185,11 @@ internal static IEnumerable<IAttribute> GetAttributes(ITypeDefinition typeDef)
185185
}
186186
}
187187

188-
internal static IAttribute GetAttribute(ITypeDefinition typeDef, KnownAttribute attributeType)
188+
internal static IAttribute? GetAttribute(ITypeDefinition typeDef, KnownAttribute attributeType)
189189
{
190190
foreach (var baseType in typeDef.GetNonInterfaceBaseTypes().Reverse())
191191
{
192-
ITypeDefinition baseTypeDef = baseType.GetDefinition();
192+
ITypeDefinition? baseTypeDef = baseType.GetDefinition();
193193
if (baseTypeDef == null)
194194
continue;
195195
var attr = baseTypeDef.GetAttribute(attributeType);
@@ -202,7 +202,7 @@ internal static IAttribute GetAttribute(ITypeDefinition typeDef, KnownAttribute
202202
internal static IEnumerable<IAttribute> GetAttributes(IMember member)
203203
{
204204
HashSet<IMember> visitedMembers = new HashSet<IMember>();
205-
do
205+
while (true)
206206
{
207207
member = member.MemberDefinition; // it's sufficient to look at the definitions
208208
if (!visitedMembers.Add(member))
@@ -214,13 +214,19 @@ internal static IEnumerable<IAttribute> GetAttributes(IMember member)
214214
{
215215
yield return attr;
216216
}
217-
} while (member.IsOverride && (member = InheritanceHelper.GetBaseMember(member)) != null);
217+
if (!member.IsOverride)
218+
break;
219+
var baseMember = GetBaseMember(member);
220+
if (baseMember == null)
221+
break;
222+
member = baseMember;
223+
}
218224
}
219225

220-
internal static IAttribute GetAttribute(IMember member, KnownAttribute attributeType)
226+
internal static IAttribute? GetAttribute(IMember member, KnownAttribute attributeType)
221227
{
222228
HashSet<IMember> visitedMembers = new HashSet<IMember>();
223-
do
229+
while (true)
224230
{
225231
member = member.MemberDefinition; // it's sufficient to look at the definitions
226232
if (!visitedMembers.Add(member))
@@ -231,7 +237,13 @@ internal static IAttribute GetAttribute(IMember member, KnownAttribute attribute
231237
var attr = member.GetAttribute(attributeType);
232238
if (attr != null)
233239
return attr;
234-
} while (member.IsOverride && (member = InheritanceHelper.GetBaseMember(member)) != null);
240+
if (!member.IsOverride)
241+
break;
242+
var baseMember = GetBaseMember(member);
243+
if (baseMember == null)
244+
break;
245+
member = baseMember;
246+
}
235247
return null;
236248
}
237249
#endregion

ICSharpCode.ILSpyX/MermaidDiagrammer/Factory.FlatMembers.cs

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,34 @@ private IField[] GetFields(ITypeDefinition type, IProperty[] properties)
4040
&& !properties.Any(p => f.ReturnType.Equals(p.ReturnType)
4141
&& Regex.IsMatch(f.Name, "_?" + p.Name, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.NonBacktracking))).ToArray();
4242

43-
private static IEnumerable<IMethod> GetMethods(ITypeDefinition type) => type.GetMethods(m =>
44-
!m.IsOperator && !m.IsCompilerGenerated()
45-
&& (m.DeclaringType == type // include methods if self-declared
46-
/* but exclude methods declared by object and their overrides, if inherited */
47-
|| (!m.DeclaringType.IsObject()
48-
&& (!m.IsOverride || !InheritanceHelper.GetBaseMember(m).DeclaringType.IsObject()))));
43+
private static IEnumerable<IMethod> GetMethods(ITypeDefinition type)
44+
{
45+
return type.GetMethods(IsDeclaredMethod);
46+
47+
bool IsDeclaredMethod(IMethod m)
48+
{
49+
if (m.IsOperator || m.IsCompilerGenerated())
50+
return false;
51+
if (m.DeclaringTypeDefinition == type)
52+
{
53+
// include methods if self-declared
54+
return true;
55+
}
56+
else
57+
{
58+
// but exclude methods declared by object and their overrides, if inherited
59+
if (m.DeclaringType.IsObject())
60+
return false;
61+
IMember? baseMember;
62+
if (m.IsOverride && (baseMember = InheritanceHelper.GetBaseMember(m)) != null)
63+
{
64+
if (baseMember.DeclaringType.IsObject())
65+
return false;
66+
}
67+
}
68+
return true;
69+
}
70+
}
4971

5072
private string FormatMethod(IMethod method)
5173
{

0 commit comments

Comments
 (0)