Skip to content

Commit b6df2bc

Browse files
authored
Merge pull request #5 from InflexCZE/fix/whitelist-member-rule-parsing
Fix whitelist parser silently dropping every member-specific entry
2 parents 77fa9fd + c3dcbe2 commit b6df2bc

3 files changed

Lines changed: 53 additions & 12 deletions

File tree

Source/DocGen/Services/ApiEntry.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -347,15 +347,15 @@ string ToConstructorString(ConstructorInfo constructorInfo, ApiEntryStringFlags
347347
{
348348
foreach (var item in DeclarersOf(constructorInfo.DeclaringType, true).Reverse())
349349
{
350-
buffer.Append(Api.GetEntry(item).ToString(ForSubCalls(flags)));
350+
buffer.Append(Api.GetEntry(item, true).ToString(ForSubCalls(flags)));
351351
buffer.Append(".");
352352
}
353353
}
354354

355355
if (flags.HasFlag(ApiEntryStringFlags.CliNames))
356356
buffer.Append(constructorInfo.Name);
357357
else
358-
buffer.Append(Api.GetEntry(constructorInfo.DeclaringType).ToString(ApiEntryStringFlags.None));
358+
buffer.Append(Api.GetEntry(constructorInfo.DeclaringType, true).ToString(ApiEntryStringFlags.None));
359359

360360
if (flags.HasFlag(ApiEntryStringFlags.ParameterTypes) || flags.HasFlag(ApiEntryStringFlags.ParameterNames))
361361
{
@@ -381,6 +381,8 @@ string ToMethodString(MethodInfo methodInfo, ApiEntryStringFlags flags)
381381
{
382382
if (methodInfo.ReturnType == typeof(void))
383383
segments.Add("void");
384+
else if (methodInfo.ReturnType.IsGenericParameter)
385+
segments.Add(methodInfo.ReturnType.Name);
384386
else
385387
segments.Add(Api.GetEntry(methodInfo.ReturnType, true).ToString(ForSubCalls(flags)));
386388
}
@@ -390,7 +392,7 @@ string ToMethodString(MethodInfo methodInfo, ApiEntryStringFlags flags)
390392
{
391393
foreach (var item in DeclarersOf(methodInfo.DeclaringType, true).Reverse())
392394
{
393-
buffer.Append(Api.GetEntry(item).ToString(ForSubCalls(flags)));
395+
buffer.Append(Api.GetEntry(item, true).ToString(ForSubCalls(flags)));
394396
buffer.Append(".");
395397
}
396398
}
@@ -408,7 +410,7 @@ string ToMethodString(MethodInfo methodInfo, ApiEntryStringFlags flags)
408410
{
409411
var genericArguments = methodInfo.GetGenericArguments();
410412
buffer.Append("<");
411-
buffer.Append(string.Join(", ", genericArguments.Select(arg => Api.GetEntry(arg).ToString(ForSubCalls(flags)))));
413+
buffer.Append(string.Join(", ", genericArguments.Select(arg => arg.IsGenericParameter ? arg.Name : Api.GetEntry(arg)?.ToString(ForSubCalls(flags)) ?? arg.Name)));
412414
buffer.Append(">");
413415
}
414416
}
@@ -448,7 +450,7 @@ string ToPropertyString(PropertyInfo propertyInfo, ApiEntryStringFlags flags)
448450
{
449451
foreach (var item in DeclarersOf(propertyInfo.DeclaringType, true).Reverse())
450452
{
451-
buffer.Append(Api.GetEntry(item).ToString(ForSubCalls(flags)));
453+
buffer.Append(Api.GetEntry(item, true).ToString(ForSubCalls(flags)));
452454
buffer.Append(".");
453455
}
454456
}

Source/DocGen/Services/Whitelist.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,32 @@ internal class Whitelist
1616
Whitelist(List<string> lines)
1717
{
1818
_entries = new List<WhitelistRule>();
19-
foreach (var entry in lines.Where(line => !string.IsNullOrWhiteSpace(line)).Select(WhitelistRule.Parse))
19+
var skippedCount = 0;
20+
foreach (var line in lines.Where(l => !string.IsNullOrWhiteSpace(l)))
2021
{
22+
WhitelistRule entry;
23+
try
24+
{
25+
entry = WhitelistRule.Parse(line);
26+
}
27+
// A member named in the whitelist no longer matches anything reflectable (e.g.
28+
// renamed/removed API, or a whitelist entry that was never valid). Assembly-not-found and
29+
// malformed-line failures are not caught here and still abort the whole load, since those
30+
// indicate a broken environment/config rather than one stale line.
31+
catch (WhitelistMemberNotFoundException)
32+
{
33+
skippedCount++;
34+
continue;
35+
}
36+
2137
if (entry is MemberRule memberRule && !_entries.Any(e => e is TypeRule typeRule && typeRule.Type == memberRule.MemberInfo.DeclaringType))
2238
_entries.Add(new TypeRule(memberRule.MemberInfo.DeclaringType, false));
2339
_entries.Add(entry);
2440
}
2541

42+
if (skippedCount > 0)
43+
Console.WriteLine($"Warning: skipped {skippedCount} whitelist entr{(skippedCount == 1 ? "y" : "ies")} whose member no longer resolves");
44+
2645
_assemblyNames = new HashSet<string>(_entries.Select(e => e.Assembly.GetName().Name).Distinct(StringComparer.OrdinalIgnoreCase), StringComparer.OrdinalIgnoreCase);
2746
}
2847

Source/DocGen/Services/WhitelistRule.cs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,17 @@ public static WhitelistRule Parse(string text)
126126
var name = "";
127127
while (parts.Count > 0)
128128
{
129-
if (name.Length > 0)
130-
name += ".";
131-
name += Translate(parts.Dequeue());
132-
var nextType = assembly.GetType(name);
129+
var candidateName = name.Length > 0 ? name + "." + Translate(parts.Peek()) : Translate(parts.Peek());
130+
var nextType = assembly.GetType(candidateName);
131+
132+
// Once a type has matched, a further failed extension means the remaining parts are
133+
// the member name (plus its generic/parameter suffix), not more of the type's own path -
134+
// leave them queued for the member-matching loop below instead of discarding them.
135+
if (nextType == null && type != null)
136+
break;
137+
138+
parts.Dequeue();
139+
name = candidateName;
133140
if (nextType != null)
134141
type = nextType;
135142
}
@@ -169,9 +176,9 @@ public static WhitelistRule Parse(string text)
169176
}
170177

171178
if (members.Count == 0)
172-
throw new InvalidOperationException("No matches");
179+
throw new WhitelistMemberNotFoundException("No matches");
173180
if (members.Count > 1)
174-
throw new InvalidOperationException("Too many matches");
181+
throw new WhitelistMemberNotFoundException("Too many matches");
175182
if (members[0] is Type nestedType)
176183
{
177184
type = nestedType;
@@ -317,4 +324,17 @@ static string ToCliTypeName(string name)
317324

318325
public abstract bool IsMatch(MemberInfo memberInfo);
319326
}
327+
328+
/// <summary>
329+
/// Thrown by <see cref="WhitelistRule.Parse" /> when a whitelist line names a specific member that
330+
/// can no longer be found (or is now ambiguous) on its declaring type - typically because the game's
331+
/// API drifted since the line was written. Callers may choose to skip just that line instead of
332+
/// aborting the whole whitelist load.
333+
/// </summary>
334+
internal class WhitelistMemberNotFoundException : InvalidOperationException
335+
{
336+
public WhitelistMemberNotFoundException(string message) : base(message)
337+
{
338+
}
339+
}
320340
}

0 commit comments

Comments
 (0)