I created a new extension in Visual Studio today! The UniqueEnumValueFixer vs extension is now available here!
https://marketplace.visualstudio.com/items?itemName=ToreAurstadIT.EXT001
The extension is actually a Code Fix for Visual Studio. It flags a warning to the developer if an enum contains multiple members
mapped to the same value. Having a collision with values for enum causes ambiguity and confusion for the developer. An enum value
has not got a single mapping from enum member to integer value.
Example like this:
Here we see that iceconverted is set to Fudge, which is the last of the colliding valued enum members. This gives code which is not clear and confusing and ambiguous. It is perfectly valid,
but programmers will perhaps sigh a bit when they see enums with multiple members mapped to same value.
The following sample code shows a violation of the rule:
enum IceCream
{
Vanilla = 0,
Chocolate = 2,
Strawberry = Vanilla,
Peach = 2
}
Here, multiple members are mapped to the same value in the enum. Strawberry and Vanilla points to the same value through assignment. And Peach is set to same value as Chocolate.
The code fix will show enums containing the violation after compiling the solution in the Errors and Warnings pane of Visual Studio.
public override void Initialize(AnalysisContext context)
{
// TODO: Consider registering other actions that act on syntax instead of or in addition to symbols
// See https://github.com/dotnet/roslyn/blob/master/docs/analyzers/Analyzer%20Actions%20Semantics.md for more information
context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType);
}
private static void AnalyzeSymbol(SymbolAnalysisContext context)
{
try
{
var namedTypeSymbol = (INamedTypeSymbol)context.Symbol;
if (namedTypeSymbol.EnumUnderlyingType != null)
{
var valueListForEnum = new List<Tuple<string, int>>();
//Debugger.Launch();
//Debugger.Break();
var typeResolved = context.Compilation.GetTypeByMetadataName(namedTypeSymbol.MetadataName) ?? context.Compilation.GetTypeByMetadataName(namedTypeSymbol.ToString());
if (typeResolved != null)
{
foreach (var member in typeResolved.GetMembers())
{
var c = member.GetType().GetRuntimeProperty("ConstantValue");
if (c == null)
{
c = member.GetType().GetRuntimeProperties().FirstOrDefault(prop =>
prop != null && prop.Name != null &&
prop.Name.Contains("IFieldSymbol.ConstantValue"));
if (c == null)
{
continue;
}
}
var v = c.GetValue(member) as int?;
if (v.HasValue)
{
valueListForEnum.Add(new Tuple<string, int>(member.Name, v.Value));
}
}
if (valueListForEnum.GroupBy(v => v.Item2).Any(g => g.Count() > 1))
{
var diagnostic = Diagnostic.Create(Rule, namedTypeSymbol.Locations[0],
namedTypeSymbol.Name);
context.ReportDiagnostic(diagnostic);
}
}
}
}
catch (Exception err)
{
Console.WriteLine(err);
}
}
The source code is available on Github here:
https://github.com/toreaurstadboss/UniqueEnumValuesAnalyzer