Skip to content

Commit

Permalink
Merge pull request #173 from microsoft/docsEnumDiscovery
Browse files Browse the repository at this point in the history
Add ability to generate enum declarations from docs
  • Loading branch information
AArnott authored Mar 8, 2021
2 parents 9ab2c0b + ecc8a66 commit 12761b2
Show file tree
Hide file tree
Showing 2 changed files with 246 additions and 63 deletions.
84 changes: 75 additions & 9 deletions src/ScrapeDocs/DocEnum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@

namespace ScrapeDocs
{
using System;
using System.Collections.Generic;
using System.Linq;

internal class DocEnum
{
internal DocEnum(bool isFlags, IReadOnlyDictionary<string, string?> memberNamesAndDocs)
internal DocEnum(bool isFlags, IReadOnlyDictionary<string, (ulong? Value, string? Doc)> members)
{
this.IsFlags = isFlags;
this.MemberNamesAndDocs = memberNamesAndDocs;
this.Members = members;
}

internal bool IsFlags { get; }

internal IReadOnlyDictionary<string, string?> MemberNamesAndDocs { get; }
internal IReadOnlyDictionary<string, (ulong? Value, string? Doc)> Members { get; }

public override bool Equals(object? obj) => this.Equals(obj as DocEnum);

Expand All @@ -24,10 +26,10 @@ public override int GetHashCode()
unchecked
{
int hash = this.IsFlags ? 1 : 0;
foreach (KeyValuePair<string, string?> entry in this.MemberNamesAndDocs)
foreach (KeyValuePair<string, (ulong? Value, string? Doc)> entry in this.Members)
{
hash += entry.Key.GetHashCode();
hash += entry.Value?.GetHashCode() ?? 0;
hash += (int)(entry.Value.Value ?? 0u);
}

return hash;
Expand All @@ -46,25 +48,89 @@ public bool Equals(DocEnum? other)
return false;
}

if (this.MemberNamesAndDocs.Count != other.MemberNamesAndDocs.Count)
if (this.Members.Count != other.Members.Count)
{
return false;
}

foreach (KeyValuePair<string, string?> entry in this.MemberNamesAndDocs)
foreach (KeyValuePair<string, (ulong? Value, string? Doc)> entry in this.Members)
{
if (!other.MemberNamesAndDocs.TryGetValue(entry.Key, out string? value))
if (!other.Members.TryGetValue(entry.Key, out (ulong? Value, string? Doc) value))
{
return false;
}

if (entry.Value != value)
if (entry.Value.Value != value.Value)
{
return false;
}
}

return true;
}

internal string? GetRecommendedName(List<(string MethodName, string ParameterName, string HelpLink, bool IsMethod)> uses)
{
string? enumName = null;
if (uses.Count == 1)
{
var oneValue = uses[0];
if (oneValue.ParameterName.Contains("flags", StringComparison.OrdinalIgnoreCase))
{
// Only appears in one method, on a parameter named something like "flags".
enumName = $"{oneValue.MethodName}Flags";
}
else
{
enumName = $"{oneValue.MethodName}_{oneValue.ParameterName}Flags";
}
}
else
{
string firstName = this.Members.Keys.First();
int commonPrefixLength = firstName.Length;
foreach (string key in this.Members.Keys)
{
commonPrefixLength = Math.Min(commonPrefixLength, GetCommonPrefixLength(key, firstName));
}

if (commonPrefixLength > 1)
{
int last_ = firstName.LastIndexOf('_', commonPrefixLength - 1);
if (last_ != -1 && last_ != commonPrefixLength - 1)
{
// Trim down to last underscore
commonPrefixLength = last_;
}

if (commonPrefixLength > 1 && firstName[commonPrefixLength - 1] == '_')
{
// The enum values share a common prefix suitable to imply a name for the enum.
enumName = firstName.Substring(0, commonPrefixLength - 1);
}
}
}

return enumName;
}

private static int GetCommonPrefixLength(ReadOnlySpan<char> first, ReadOnlySpan<char> second)
{
int count = 0;
int minLength = Math.Min(first.Length, second.Length);
for (int i = 0; i < minLength; i++)
{
if (first[i] == second[i])
{
count++;
}
else
{
break;
}
}

return count;
}
}
}
Loading

0 comments on commit 12761b2

Please sign in to comment.