private void AddNonFlagsEnumConstantValue(INamedTypeSymbol enumType, object constantValue) { var underlyingSpecialType = enumType.EnumUnderlyingType.SpecialType; var constantValueULong = EnumUtilities.ConvertEnumUnderlyingTypeToUInt64( constantValue, underlyingSpecialType ); var enumFields = ArrayBuilder <EnumField> .GetInstance(); GetSortedEnumFields(enumType, enumFields); // See if there's a member with this value. If so, then use that. var match = EnumField.FindValue(enumFields, constantValueULong); if (!match.IsDefault) { ((IFieldSymbol)match.IdentityOpt).Accept(this.NotFirstVisitor); } else { // Otherwise, just add the enum as a literal. AddExplicitlyCastedLiteralValue(enumType, underlyingSpecialType, constantValue); } enumFields.Free(); }
private void AddFlagsEnumConstantValue( INamedTypeSymbol enumType, object constantValue, ArrayBuilder <EnumField> allFieldsAndValues, ArrayBuilder <EnumField> usedFieldsAndValues, bool preferNumericValueOrExpandedFlags ) { var underlyingSpecialType = enumType.EnumUnderlyingType.SpecialType; var constantValueULong = EnumUtilities.ConvertEnumUnderlyingTypeToUInt64( constantValue, underlyingSpecialType ); var result = constantValueULong; // We will not optimize this code further to keep it maintainable. There are some // boundary checks that can be applied to minimize the comparisons required. This code // works the same for the best/worst case. In general the number of items in an enum are // sufficiently small and not worth the optimization. if (result != 0) { foreach (EnumField fieldAndValue in allFieldsAndValues) { var valueAtIndex = fieldAndValue.Value; // In the case that we prefer a numeric value or expanded flags, we don't want to add the // field matching this precise value because we'd rather see the constituent parts. if (preferNumericValueOrExpandedFlags && valueAtIndex == constantValueULong) { continue; } if (valueAtIndex != 0 && (result & valueAtIndex) == valueAtIndex) { usedFieldsAndValues.Add(fieldAndValue); result -= valueAtIndex; if (result == 0) { break; } } } } // We were able to represent this number as a bitwise or of valid flags. if (result == 0 && usedFieldsAndValues.Count > 0) { // We want to emit the fields in lower to higher value. So we walk backward. for (int i = usedFieldsAndValues.Count - 1; i >= 0; i--) { if (i != (usedFieldsAndValues.Count - 1)) { AddSpace(); AddBitwiseOr(); AddSpace(); } ((IFieldSymbol)usedFieldsAndValues[i].IdentityOpt).Accept(this.NotFirstVisitor); } } else { // We couldn't find fields to OR together to make the value. if (preferNumericValueOrExpandedFlags) { AddLiteralValue(underlyingSpecialType, constantValue); return; } // If we had 0 as the value, and there's an enum value equal to 0, then use that. var zeroField = constantValueULong == 0 ? EnumField.FindValue(allFieldsAndValues, 0) : default(EnumField); if (!zeroField.IsDefault) { ((IFieldSymbol)zeroField.IdentityOpt).Accept(this.NotFirstVisitor); } else { // Add anything else in as a literal value. AddExplicitlyCastedLiteralValue(enumType, underlyingSpecialType, constantValue); } } }