Skip to content

Commit 81e0a93

Browse files
authored
Don't add values to enums that can't be parsed (#1836)
* Don't add values to enums that can't be parsed * Fix test case * Oops
1 parent f2f48dc commit 81e0a93

File tree

2 files changed

+47
-37
lines changed

2 files changed

+47
-37
lines changed

src/Generator/Library.cs

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -103,22 +103,29 @@ public static Enumeration GetEnumWithMatchingItem(this ASTContext context, strin
103103
/// as well as all previously discovered <see cref="Enumeration.Items"/>. The intent is to
104104
/// preserve sign information about the values held in <paramref name="enum"/>.
105105
/// </remarks>
106-
public static Enumeration.Item GenerateEnumItemFromMacro(this Enumeration @enum,
107-
MacroDefinition macro)
106+
public static bool TryGenerateEnumItemFromMacro(this Enumeration @enum,
107+
MacroDefinition macro, out Enumeration.Item item)
108108
{
109-
var (value, type) = ParseEnumItemMacroExpression(macro, @enum);
109+
if (!TryParseEnumItemMacroExpression(macro, @enum, out var result))
110+
{
111+
item = null;
112+
return false;
113+
}
114+
115+
var (value, type) = result;
110116
if (type > @enum.BuiltinType.Type)
111117
{
112118
@enum.BuiltinType = new BuiltinType(type);
113119
@enum.Type = @enum.BuiltinType;
114120
}
115-
return new Enumeration.Item
121+
item = new Enumeration.Item
116122
{
117123
Name = macro.Name,
118124
Expression = macro.Expression,
119125
Value = value,
120126
Namespace = @enum
121127
};
128+
return true;
122129
}
123130

124131
static object EvaluateEnumExpression(string expr, Enumeration @enum)
@@ -154,7 +161,7 @@ static object EvaluateEnumExpression(string expr, Enumeration @enum)
154161
/// evaluator biases towards returning <see cref="int"/> values: it doesn't attempt to
155162
/// discover that a value could be stored in a <see cref="byte"/>.
156163
/// </returns>
157-
static (ulong value, PrimitiveType type) ParseEnumItemMacroExpression(MacroDefinition macro, Enumeration @enum)
164+
static bool TryParseEnumItemMacroExpression(MacroDefinition macro, Enumeration @enum, out (ulong value, PrimitiveType type) item)
158165
{
159166
var expression = macro.Expression;
160167

@@ -171,38 +178,40 @@ static object EvaluateEnumExpression(string expr, Enumeration @enum)
171178
// Verify we have some sort of integer type. Enums can have negative values: record
172179
// that fact so that we can set the underlying primitive type correctly in the enum
173180
// item.
174-
switch (System.Type.GetTypeCode(eval.GetType()))
181+
item = System.Type.GetTypeCode(eval.GetType()) switch
175182
{
176183
// Must unbox eval which is typed as object to be able to cast it to a ulong.
177-
case TypeCode.SByte: return ((ulong)(sbyte)eval, PrimitiveType.SChar);
178-
case TypeCode.Int16: return ((ulong)(short)eval, PrimitiveType.Short);
179-
case TypeCode.Int32: return ((ulong)(int)eval, PrimitiveType.Int);
180-
case TypeCode.Int64: return ((ulong)(long)eval, PrimitiveType.LongLong);
184+
TypeCode.SByte => ((ulong)(sbyte)eval, PrimitiveType.SChar),
185+
TypeCode.Int16 => ((ulong)(short)eval, PrimitiveType.Short),
186+
TypeCode.Int32 => ((ulong)(int)eval, PrimitiveType.Int),
187+
TypeCode.Int64 => ((ulong)(long)eval, PrimitiveType.LongLong),
181188

182-
case TypeCode.Byte: return ((byte)eval, PrimitiveType.UChar);
183-
case TypeCode.UInt16: return ((ushort)eval, PrimitiveType.UShort);
184-
case TypeCode.UInt32: return ((uint)eval, PrimitiveType.UInt);
185-
case TypeCode.UInt64: return ((ulong)eval, PrimitiveType.ULongLong);
189+
TypeCode.Byte => ((byte)eval, PrimitiveType.UChar),
190+
TypeCode.UInt16 => ((ushort)eval, PrimitiveType.UShort),
191+
TypeCode.UInt32 => ((uint)eval, PrimitiveType.UInt),
192+
TypeCode.UInt64 => ((ulong)eval, PrimitiveType.ULongLong),
186193

187-
case TypeCode.Char: return ((char)eval, PrimitiveType.UShort);
194+
TypeCode.Char => ((char)eval, PrimitiveType.UShort),
188195
// C++ allows booleans as enum values - they're translated to 1, 0.
189-
case TypeCode.Boolean: return ((bool)eval ? 1UL : 0UL, PrimitiveType.UChar);
196+
TypeCode.Boolean => ((bool)eval ? 1UL : 0UL, PrimitiveType.UChar),
190197

191-
default: throw new Exception($"Expression {expression} is not a valid expression type for an enum");
192-
}
198+
_ => throw new Exception($"Expression {expression} is not a valid expression type for an enum")
199+
};
200+
201+
return true;
193202
}
194203
catch (Exception ex)
195204
{
196-
// TODO: This should just throw, but we have a pre-existing behavior that expects malformed
197-
// macro expressions to default to 0, see CSharp.h (MY_MACRO_TEST2_0), so do it for now.
205+
// TODO: There should be a toggle to just throw here instead.
198206

199207
// Like other paths, we can however, write a diagnostic message to the console.
200208

201209
Diagnostics.PushIndent();
202210
Diagnostics.Warning($"Unable to translate macro '{macro.Name}' to en enum value: {ex.Message}");
203211
Diagnostics.PopIndent();
204212

205-
return (0, PrimitiveType.Int);
213+
item = default;
214+
return false;
206215
}
207216
}
208217

@@ -311,16 +320,18 @@ TranslationUnit GetUnitFromItems(List<Enumeration.Item> list)
311320
if (@enum.Items.Exists(it => it.Name == macro.Name))
312321
continue;
313322

314-
var item = @enum.GenerateEnumItemFromMacro(macro);
315-
@enum.AddItem(item);
316-
macro.Enumeration = @enum;
323+
if (@enum.TryGenerateEnumItemFromMacro(macro, out var item))
324+
{
325+
@enum.AddItem(item);
326+
macro.Enumeration = @enum;
327+
}
317328
}
318329

319330
if (@enum.Items.Count <= 0)
320331
return @enum;
321332

322333
// The value of @enum.BuiltinType has been adjusted on the fly via
323-
// GenerateEnumItemFromMacro. However, its notion of PrimitiveType corresponds with
334+
// TryGenerateEnumItemFromMacro. However, its notion of PrimitiveType corresponds with
324335
// what the ExpressionEvaluator returns. In particular, the expression "1" will result
325336
// in PrimitiveType.Int from the expression evaluator. Narrow the type to account for
326337
// types narrower than int.

tests/dotnet/CSharp/CSharp.Tests.cs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1524,18 +1524,17 @@ public void TestMyMacroTestEnum()
15241524
[Test]
15251525
public void TestMyMacro2TestEnum()
15261526
{
1527-
var a = (MyMacroTest2Enum)0;
1528-
var b = (MyMacroTest2Enum)1;
1529-
var c = (MyMacroTest2Enum)0x2;
1530-
var d = (MyMacroTest2Enum)(1 << 2);
1531-
var e = (MyMacroTest2Enum)(b | c);
1532-
var f = (MyMacroTest2Enum)(b | c | d);
1533-
var g = (MyMacroTest2Enum)(1 << 3);
1534-
var h = (MyMacroTest2Enum)((1 << 4) - 1);
1535-
Assert.IsTrue(a == MyMacroTest2Enum.MY_MACRO_TEST2_0 && b == MyMacroTest2Enum.MY_MACRO_TEST2_1 &&
1536-
c == MyMacroTest2Enum.MY_MACRO_TEST2_2 && d == MyMacroTest2Enum.MY_MACRO_TEST2_3 &&
1537-
e == MyMacroTest2Enum.MY_MACRO_TEST2_1_2 && f == MyMacroTest2Enum.MY_MACRO_TEST2_1_2_3 &&
1538-
g == MyMacroTest2Enum.MY_MACRO_TEST2_4 && h == MyMacroTest2Enum.MY_MACRO_TEST2ALL);
1527+
var a = (MyMacroTest2Enum)1;
1528+
var b = (MyMacroTest2Enum)0x2;
1529+
var c = (MyMacroTest2Enum)(1 << 2);
1530+
var d = (MyMacroTest2Enum)(a | b);
1531+
var e = (MyMacroTest2Enum)(a | b | c);
1532+
var f = (MyMacroTest2Enum)(1 << 3);
1533+
var g = (MyMacroTest2Enum)((1 << 4) - 1);
1534+
Assert.IsTrue(a == MyMacroTest2Enum.MY_MACRO_TEST2_1 && b == MyMacroTest2Enum.MY_MACRO_TEST2_2 &&
1535+
c == MyMacroTest2Enum.MY_MACRO_TEST2_3 && d == MyMacroTest2Enum.MY_MACRO_TEST2_1_2 &&
1536+
e == MyMacroTest2Enum.MY_MACRO_TEST2_1_2_3 && f == MyMacroTest2Enum.MY_MACRO_TEST2_4 &&
1537+
g == MyMacroTest2Enum.MY_MACRO_TEST2ALL);
15391538
}
15401539

15411540
[Test]

0 commit comments

Comments
 (0)