Skip to content

Commit f145ead

Browse files
authored
Improve inheritance resolver for plaintext render (#29)
1 parent a4ae9f7 commit f145ead

File tree

7 files changed

+205
-228
lines changed

7 files changed

+205
-228
lines changed

src/Render/BitzArt.XDoc.PlainText/Extensions/TypeExtensions.cs

Lines changed: 0 additions & 15 deletions
This file was deleted.
Lines changed: 35 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System.Reflection;
2-
using System.Xml;
32

43
namespace BitzArt.XDoc;
54

@@ -8,118 +7,91 @@ namespace BitzArt.XDoc;
87
/// </summary>
98
internal static class InheritanceResolver
109
{
11-
public static MemberInfo? GetTargetMember(MemberInfo sourceMember, XmlNode? node)
10+
public static MemberInfo? GetTargetMember(MemberInfo sourceMember)
1211
{
1312
return sourceMember switch
1413
{
1514
Type type => FindTargetType(type),
16-
_ => FindTargetMember(sourceMember.DeclaringType!, sourceMember, false)
15+
MemberInfo => FindTargetMember(sourceMember.DeclaringType!, sourceMember)
1716
};
1817
}
1918

20-
private static MemberInfo? FindTargetType(Type type)
19+
private static Type? FindTargetType(Type type)
2120
{
2221
if (type.BaseType is not null)
2322
{
2423
return type.BaseType;
2524
}
2625

27-
return type.GetImmediateInterfaces().FirstOrDefault();
26+
return GetImmediateInterfaces(type).FirstOrDefault();
2827
}
2928

30-
private static MemberInfo? FindTargetMember(Type type, MemberInfo sourceMember, bool checkOwnMembers = false)
29+
private static MemberInfo? FindTargetMember(Type type, MemberInfo sourceMember)
3130
{
32-
if (checkOwnMembers)
31+
// 1. Check base type members
32+
if (type.BaseType is not null)
3333
{
34-
if (CheckPresence(type, sourceMember, out var found))
34+
if (CheckPresence(type.BaseType, sourceMember, out var foundInBaseType))
3535
{
36-
return found;
36+
return foundInBaseType;
3737
}
3838
}
3939

40-
if (type.BaseType != null)
40+
// 2. Check own immediate interfaces' members
41+
foreach (var immediateInterface in GetImmediateInterfaces(type))
4142
{
42-
if (CheckPresence(type.BaseType, sourceMember, out var foundInBaseType))
43+
if (CheckPresence(immediateInterface, sourceMember, out var found))
4344
{
44-
return foundInBaseType;
45+
return found;
4546
}
46-
47-
var result = FindTargetMember(type.BaseType, sourceMember, true);
47+
48+
var result = FindTargetMember(immediateInterface, sourceMember);
4849

4950
if (result is not null)
5051
{
5152
return result;
5253
}
5354
}
5455

55-
foreach (var immediateInterface in type.GetImmediateInterfaces())
56+
// 3. Recursively visit base type (if any).
57+
if (type.BaseType is not null)
5658
{
57-
if (CheckPresence(immediateInterface, sourceMember, out var found))
58-
{
59-
return found;
60-
}
61-
62-
var result = FindTargetMember(immediateInterface, sourceMember, true);
59+
var result = FindTargetMember(type.BaseType, sourceMember);
6360

6461
if (result is not null)
6562
{
6663
return result;
6764
}
6865
}
66+
6967

7068
return null;
7169
}
7270

7371
private static bool CheckPresence(Type type, MemberInfo sourceMember, out MemberInfo? found)
7472
{
75-
var memberInfos = type.GetMembers();
76-
77-
foreach (var member in memberInfos)
73+
found = sourceMember switch
7874
{
79-
if (member.MemberType != sourceMember.MemberType)
80-
{
81-
continue;
82-
}
75+
PropertyInfo propertyInfo => type.GetProperty(propertyInfo.Name),
8376

84-
if (member.Name != sourceMember.Name)
85-
{
86-
continue;
87-
}
77+
FieldInfo fieldInfo => type.GetField(fieldInfo.Name),
8878

89-
if (sourceMember is MethodInfo sourceMethod && member is MethodInfo targetMethod)
90-
{
91-
var sourceParams = sourceMethod.GetParameters();
92-
var targetParams = targetMethod.GetParameters();
93-
94-
if (sourceParams.Length != targetParams.Length)
95-
{
96-
continue;
97-
}
98-
99-
var parametersMatch = true;
100-
101-
for (var i = 0; i < sourceParams.Length; i++)
102-
{
103-
if (sourceParams[i].ParameterType != targetParams[i].ParameterType)
104-
{
105-
parametersMatch = false;
106-
break;
107-
}
108-
}
109-
110-
if (!parametersMatch)
111-
{
112-
continue;
113-
}
114-
}
79+
MethodInfo methodInfo => type.GetMethod(
80+
methodInfo.Name,
81+
methodInfo.GetGenericArguments().Length,
82+
[.. methodInfo.GetParameters().Select(p => p.ParameterType)]),
11583

116-
found = member;
84+
_ => throw new NotSupportedException()
85+
};
11786

118-
return true;
119-
}
87+
return found is not null;
88+
}
12089

121-
found = null;
90+
private static IEnumerable<Type> GetImmediateInterfaces(Type type)
91+
{
92+
var inheritedInterfaces = type.GetInterfaces().SelectMany(i => i.GetInterfaces()).ToList();
93+
inheritedInterfaces.AddRange(type.BaseType?.GetInterfaces() ?? []);
12294

123-
return false;
95+
return type.GetInterfaces().Except(inheritedInterfaces);
12496
}
12597
}

src/Render/BitzArt.XDoc.PlainText/PlainTextRenderer.cs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ private string Normalize(string input)
8282
.Where(o => !string.IsNullOrWhiteSpace(o))
8383
.ToList();
8484

85-
var separator = _options.ForceSingleLine ? " " : "\n";
85+
var separator = _options.Trim ? " " : "\n";
8686

8787
return string.Join(separator, lines);
8888
}
@@ -122,24 +122,29 @@ private string RenderXmlElement(XmlElement element, MemberInfo? target)
122122
if (element.Name == "inheritdoc")
123123
{
124124
// Direct inheritance
125-
return RenderDirectInheritance(element, target);
125+
return RenderDirectInheritance(target);
126126
}
127127

128128
var builder = new StringBuilder();
129129

130130
foreach (XmlNode child in element.ChildNodes)
131131
{
132-
builder.Append(Render(child, null));
132+
builder.Append(Render(child, target));
133133
}
134134

135135
return builder.ToString();
136136
}
137137

138138
private string RenderReference(XmlElement element)
139139
{
140-
var cref = new MemberIdentifier(element.Attributes["cref"]!.Value);
140+
MemberIdentifier.TryCreate(element.Attributes["cref"]?.Value, out var cref);
141141

142-
var type = _options.UseShortTypeNames ? cref.ShortType : cref.Type;
142+
if (cref == null)
143+
{
144+
return string.Empty;
145+
}
146+
147+
var type = _options.RemoveNamespace ? cref.ShortType : cref.Type;
143148

144149
if (cref.IsMember)
145150
{
@@ -149,14 +154,14 @@ private string RenderReference(XmlElement element)
149154
return type;
150155
}
151156

152-
private string RenderDirectInheritance(XmlElement element, MemberInfo? target)
157+
private string RenderDirectInheritance(MemberInfo? target)
153158
{
154159
if (target == null)
155160
{
156161
return string.Empty;
157162
}
158163

159-
var targetMember = InheritanceResolver.GetTargetMember(target, element);
164+
var targetMember = InheritanceResolver.GetTargetMember(target);
160165

161166
if (targetMember == null)
162167
{
@@ -165,6 +170,11 @@ private string RenderDirectInheritance(XmlElement element, MemberInfo? target)
165170

166171
var documentationElement = _xdoc.Get(targetMember);
167172

173+
if (documentationElement == null)
174+
{
175+
return RenderDirectInheritance(targetMember);
176+
}
177+
168178
return Render(documentationElement);
169179
}
170180
}

src/Render/BitzArt.XDoc.PlainText/RendererOptions.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@ public record RendererOptions
1010
/// When set to true, any line breaks in the content will be removed or replaced.
1111
/// When set to false, the content will maintain its original line structure.
1212
/// </summary>
13-
public bool ForceSingleLine { get; init; } = true;
13+
public bool Trim { get; init; } = true;
1414

1515
/// <summary>
16-
/// Indicating whether type names should be rendered in their short form.
17-
/// When set to true, simple type names will be used (e.g., "string" instead of "System.String").
18-
/// When set to false, fully qualified type names will be used.
16+
/// Whether to remove the namespace from the type names.
1917
/// </summary>
20-
public bool UseShortTypeNames { get; init; } = true;
18+
public bool RemoveNamespace { get; init; } = true;
2119
}

src/Render/BitzArt.XDoc.PlainText/XDocExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ public static string ToPlainText(this DocumentationElement? documentation)
1919

2020
return new PlainTextRenderer(documentation.Source, new RendererOptions
2121
{
22-
ForceSingleLine = true,
23-
UseShortTypeNames = true
22+
Trim = true,
23+
RemoveNamespace = true
2424
}).Render(documentation);
2525
}
2626
}

0 commit comments

Comments
 (0)