-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathFactory.TypeIds.cs
58 lines (46 loc) · 2.79 KB
/
Factory.TypeIds.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
using ICSharpCode.Decompiler.TypeSystem;
namespace NetAmermaid
{
using CD = ClassDiagrammer;
public partial class ClassDiagrammerFactory
{
/// <summary>Generates a dictionary of unique and short, but human readable identifiers for
/// <paramref name="types"/>to be able to safely reference them in any combination.</summary>
private static Dictionary<IType, string> GenerateUniqueIds(IEnumerable<ITypeDefinition> types)
{
Dictionary<IType, string> uniqueIds = new();
var groups = types.GroupBy(t => t.Name);
// simplified handling for the majority of unique types
foreach (var group in groups.Where(g => g.Count() == 1))
uniqueIds[group.First()] = SanitizeTypeName(group.Key);
// number non-unique types
foreach (var group in groups.Where(g => g.Count() > 1))
{
var counter = 0;
foreach (var type in group) uniqueIds[type] = type.Name + ++counter;
}
return uniqueIds;
}
private string GetId(IType type) => GetIdAndOpenGeneric(type).id;
/// <summary>For a non- or open generic <paramref name="type"/>, returns a unique identifier and null.
/// For a closed generic <paramref name="type"/>, returns the open generic type and the unique identifier of it.
/// That helps connecting closed generic references (e.g. Store<int>) to their corresponding
/// open generic <see cref="CD.Type"/> (e.g. Store<T>) like in <see cref="BuildRelationship(IType, string?)"/>.</summary>
private (string id, IType? openGeneric) GetIdAndOpenGeneric(IType type)
{
// get open generic type if type is a closed generic (i.e. has type args none of which are parameters)
var openGeneric = type is ParameterizedType generic && !generic.TypeArguments.Any(a => a is ITypeParameter)
? generic.GenericType : null;
type = openGeneric ?? type; // reference open instead of closed generic type
if (uniqueIds!.TryGetValue(type, out var uniqueId)) return (uniqueId, openGeneric); // types included by FilterTypes
// types excluded by FilterTypes
string? typeParams = type.TypeParameterCount == 0 ? null : ("_" + type.TypeParameters.Select(GetId).Join("_"));
var id = SanitizeTypeName(type.FullName.Replace('.', '_'))
+ typeParams; // to achive uniqueness for types with same FullName (i.e. generic overloads)
uniqueIds![type] = id; // update dictionary to avoid re-generation
return (id, openGeneric);
}
private static string SanitizeTypeName(string typeName)
=> typeName.Replace('<', '_').Replace('>', '_'); // for module of executable
}
}