Skip to content

Commit 6b3010e

Browse files
committed
C#: Extract enum underlying type from IL
1 parent c7d6c42 commit 6b3010e

File tree

5 files changed

+106
-36
lines changed

5 files changed

+106
-36
lines changed

csharp/extractor/Semmle.Extraction.CIL/Entities/TypeDefinitionType.cs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,15 @@ public override IEnumerable<IExtractionProduct> Contents
212212
var @base = (Type)Cx.CreateGeneric(this, td.BaseType);
213213
yield return @base;
214214
yield return Tuples.cil_base_class(this, @base);
215+
216+
if (IsSystemEnum(td.BaseType) &&
217+
GetUnderlyingEnumType() is var underlying &&
218+
underlying.HasValue)
219+
{
220+
var underlyingType = Cx.Create(underlying.Value);
221+
yield return underlyingType;
222+
yield return Tuples.cil_enum_underlying_type(this, underlyingType);
223+
}
215224
}
216225

217226
foreach (var @interface in td.GetInterfaceImplementations().Select(i => Cx.MdReader.GetInterfaceImplementation(i)))
@@ -226,6 +235,59 @@ public override IEnumerable<IExtractionProduct> Contents
226235
}
227236
}
228237

238+
private bool IsSystemEnum(EntityHandle baseType)
239+
{
240+
return baseType.Kind switch
241+
{
242+
HandleKind.TypeReference => IsSystemEnum((TypeReferenceHandle)baseType),
243+
HandleKind.TypeDefinition => IsSystemEnum((TypeDefinitionHandle)baseType),
244+
_ => false,
245+
};
246+
}
247+
248+
private bool IsSystemEnum(TypeReferenceHandle baseType)
249+
{
250+
var baseTypeReference = Cx.MdReader.GetTypeReference(baseType);
251+
252+
return IsSystemEnum(baseTypeReference.Name, baseTypeReference.Namespace);
253+
}
254+
255+
private bool IsSystemEnum(TypeDefinitionHandle baseType)
256+
{
257+
var baseTypeDefinition = Cx.MdReader.GetTypeDefinition(baseType);
258+
259+
return IsSystemEnum(baseTypeDefinition.Name, baseTypeDefinition.Namespace);
260+
}
261+
262+
private bool IsSystemEnum(StringHandle typeName, StringHandle namespaceName)
263+
{
264+
return Cx.MdReader.StringComparer.Equals(typeName, "Enum") &&
265+
!namespaceName.IsNil &&
266+
Cx.MdReader.StringComparer.Equals(namespaceName, "System");
267+
}
268+
269+
internal PrimitiveTypeCode? GetUnderlyingEnumType()
270+
{
271+
foreach (var handle in td.GetFields())
272+
{
273+
var field = Cx.MdReader.GetFieldDefinition(handle);
274+
if ((field.Attributes & FieldAttributes.Static) != 0)
275+
{
276+
continue;
277+
}
278+
279+
var blob = Cx.MdReader.GetBlobReader(field.Signature);
280+
if (blob.ReadSignatureHeader().Kind != SignatureKind.Field)
281+
{
282+
break;
283+
}
284+
285+
return (PrimitiveTypeCode)blob.ReadByte();
286+
}
287+
288+
return null;
289+
}
290+
229291
internal override Method LookupMethod(StringHandle name, BlobHandle signature)
230292
{
231293
foreach (var h in td.GetMethods())

csharp/extractor/Semmle.Extraction.CIL/Tuples.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ internal static Tuple cil_array_type(ArrayType array, Type element, int rank) =>
3232
internal static Tuple cil_base_class(Type t, Type @base) =>
3333
new Tuple("cil_base_class", t, @base);
3434

35+
internal static Tuple cil_enum_underlying_type(Type t, PrimitiveType underlying) =>
36+
new Tuple("cil_enum_underlying_type", t, underlying);
37+
3538
internal static Tuple cil_base_interface(Type t, Type @base) =>
3639
new Tuple("cil_base_interface", t, @base);
3740

csharp/ql/src/semmle/code/cil/Types.qll

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,12 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, @cil_valueorreftype {
4747
class Enum extends ValueOrRefType {
4848
Enum() { this.isEnum() }
4949

50-
// Note that we don't actually use the proper internal representation yet.
51-
override IntType getUnderlyingType() { any() }
50+
override IntegralType getUnderlyingType() {
51+
cil_enum_underlying_type(this, result)
52+
or
53+
not exists(IntegralType underlying | cil_enum_underlying_type(this, underlying)) and
54+
result = any(IntType i)
55+
}
5256
}
5357

5458
/** A `class`. */

csharp/ql/src/semmlecode.csharp.dbscheme

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1803,6 +1803,7 @@ cil_newslot(int id: @cil_method ref);
18031803

18041804
cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref);
18051805
cil_base_interface(int id: @cil_type ref, int base: @cil_type ref);
1806+
cil_enum_underlying_type(unique int id: @cil_type ref, int underlying: @cil_type ref);
18061807

18071808
#keyset[unbound, index]
18081809
cil_type_parameter(

csharp/ql/test/library-tests/cil/enums/enums.expected

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
| Interop.Advapi32.ActivityControl | int |
1+
| Interop.Advapi32.ActivityControl | uint |
22
| Interop.BOOL | int |
33
| Interop.Error | int |
44
| Interop.Globalization.ResultCode | int |
@@ -11,19 +11,19 @@
1111
| Interop.Sys.LockOperations | int |
1212
| Interop.Sys.NodeType | int |
1313
| Interop.Sys.OpenFlags | int |
14-
| Interop.Sys.PollEvents | int |
14+
| Interop.Sys.PollEvents | short |
1515
| Interop.Sys.SeekWhence | int |
1616
| Interop.Sys.SysConfName | int |
1717
| Interop.Sys.SysLogPriority | int |
1818
| System.AttributeTargets | int |
1919
| System.Base64FormattingOptions | int |
2020
| System.Buffers.ArrayPoolEventSource.BufferAllocatedReason | int |
2121
| System.Buffers.OperationStatus | int |
22-
| System.Buffers.Text.FormattingHelpers.HexCasing | int |
23-
| System.Buffers.Text.Utf8Parser.ComponentParseResult | int |
22+
| System.Buffers.Text.FormattingHelpers.HexCasing | uint |
23+
| System.Buffers.Text.Utf8Parser.ComponentParseResult | byte |
2424
| System.Buffers.Text.Utf8Parser.ParseNumberOptions | int |
2525
| System.Buffers.TlsOverPerCoreLockedStacksArrayPool.MemoryPressure | int |
26-
| System.Collections.Generic.InsertionBehavior | int |
26+
| System.Collections.Generic.InsertionBehavior | byte |
2727
| System.ComponentModel.EditorBrowsableState | int |
2828
| System.Configuration.Assemblies.AssemblyHashAlgorithm | int |
2929
| System.Configuration.Assemblies.AssemblyVersionCompatibility | int |
@@ -46,12 +46,12 @@
4646
| System.Diagnostics.SymbolStore.SymAddressKind | int |
4747
| System.Diagnostics.Tracing.ControllerCommand | int |
4848
| System.Diagnostics.Tracing.EventActivityOptions | int |
49-
| System.Diagnostics.Tracing.EventChannel | int |
49+
| System.Diagnostics.Tracing.EventChannel | byte |
5050
| System.Diagnostics.Tracing.EventChannelType | int |
5151
| System.Diagnostics.Tracing.EventCommand | int |
5252
| System.Diagnostics.Tracing.EventFieldFormat | int |
5353
| System.Diagnostics.Tracing.EventFieldTags | int |
54-
| System.Diagnostics.Tracing.EventKeywords | int |
54+
| System.Diagnostics.Tracing.EventKeywords | long |
5555
| System.Diagnostics.Tracing.EventLevel | int |
5656
| System.Diagnostics.Tracing.EventManifestOptions | int |
5757
| System.Diagnostics.Tracing.EventOpcode | int |
@@ -61,7 +61,7 @@
6161
| System.Diagnostics.Tracing.EventSourceSettings | int |
6262
| System.Diagnostics.Tracing.EventTags | int |
6363
| System.Diagnostics.Tracing.EventTask | int |
64-
| System.Diagnostics.Tracing.ManifestEnvelope.ManifestFormats | int |
64+
| System.Diagnostics.Tracing.ManifestEnvelope.ManifestFormats | byte |
6565
| System.Diagnostics.Tracing.TraceLoggingDataType | int |
6666
| System.Enum | int |
6767
| System.Environment.SpecialFolder | int |
@@ -77,33 +77,33 @@
7777
| System.Globalization.BidiCategory | int |
7878
| System.Globalization.CalendarAlgorithmType | int |
7979
| System.Globalization.CalendarDataType | int |
80-
| System.Globalization.CalendarId | int |
80+
| System.Globalization.CalendarId | ushort |
8181
| System.Globalization.CalendarWeekRule | int |
8282
| System.Globalization.CalendricalCalculationsHelper.CorrectionAlgorithm | int |
8383
| System.Globalization.CompareOptions | int |
84-
| System.Globalization.CultureData.LocaleGroupingData | int |
85-
| System.Globalization.CultureData.LocaleNumberData | int |
86-
| System.Globalization.CultureData.LocaleStringData | int |
84+
| System.Globalization.CultureData.LocaleGroupingData | uint |
85+
| System.Globalization.CultureData.LocaleNumberData | uint |
86+
| System.Globalization.CultureData.LocaleStringData | uint |
8787
| System.Globalization.CultureTypes | int |
8888
| System.Globalization.DateTimeFormatFlags | int |
8989
| System.Globalization.DateTimeFormatInfoScanner.FoundDatePattern | int |
9090
| System.Globalization.DateTimeStyles | int |
9191
| System.Globalization.DigitShapes | int |
9292
| System.Globalization.FORMATFLAGS | int |
9393
| System.Globalization.GregorianCalendarTypes | int |
94-
| System.Globalization.HebrewNumber.HS | int |
95-
| System.Globalization.HebrewNumber.HebrewToken | int |
94+
| System.Globalization.HebrewNumber.HS | sbyte |
95+
| System.Globalization.HebrewNumber.HebrewToken | short |
9696
| System.Globalization.HebrewNumberParsingState | int |
9797
| System.Globalization.LocaleDataParts | int |
9898
| System.Globalization.MonthNameStyles | int |
9999
| System.Globalization.NumberStyles | int |
100-
| System.Globalization.TextInfo.Tristate | int |
100+
| System.Globalization.TextInfo.Tristate | byte |
101101
| System.Globalization.TimeSpanFormat.StandardFormat | int |
102-
| System.Globalization.TimeSpanParse.TTT | int |
103-
| System.Globalization.TimeSpanParse.TimeSpanStandardStyles | int |
102+
| System.Globalization.TimeSpanParse.TTT | byte |
103+
| System.Globalization.TimeSpanParse.TimeSpanStandardStyles | byte |
104104
| System.Globalization.TimeSpanStyles | int |
105105
| System.Globalization.UnicodeCategory | int |
106-
| System.Guid.GuidParseThrowStyle | int |
106+
| System.Guid.GuidParseThrowStyle | byte |
107107
| System.IO.FileAccess | int |
108108
| System.IO.FileAttributes | int |
109109
| System.IO.FileMode | int |
@@ -113,7 +113,7 @@
113113
| System.IO.SeekOrigin | int |
114114
| System.LazyState | int |
115115
| System.MidpointRounding | int |
116-
| System.Number.NumberBufferKind | int |
116+
| System.Number.NumberBufferKind | byte |
117117
| System.Number.ParsingStatus | int |
118118
| System.ParseFailureKind | int |
119119
| System.ParseFlags | int |
@@ -123,7 +123,7 @@
123123
| System.Reflection.Associates.Attributes | int |
124124
| System.Reflection.BindingFlags | int |
125125
| System.Reflection.CallingConventions | int |
126-
| System.Reflection.CorElementType | int |
126+
| System.Reflection.CorElementType | byte |
127127
| System.Reflection.CustomAttributeEncoding | int |
128128
| System.Reflection.Emit.AssemblyBuilderAccess | int |
129129
| System.Reflection.Emit.DynamicResolver.SecurityControlFlags | int |
@@ -133,17 +133,17 @@
133133
| System.Reflection.Emit.OperandType | int |
134134
| System.Reflection.Emit.PEFileKinds | int |
135135
| System.Reflection.Emit.PackingSize | int |
136-
| System.Reflection.Emit.ScopeAction | int |
136+
| System.Reflection.Emit.ScopeAction | sbyte |
137137
| System.Reflection.Emit.StackBehaviour | int |
138138
| System.Reflection.Emit.TypeKind | int |
139139
| System.Reflection.Emit.TypeNameBuilder.Format | int |
140140
| System.Reflection.EventAttributes | int |
141141
| System.Reflection.ExceptionHandlingClauseOptions | int |
142142
| System.Reflection.FieldAttributes | int |
143143
| System.Reflection.GenericParameterAttributes | int |
144-
| System.Reflection.INVOCATION_FLAGS | int |
144+
| System.Reflection.INVOCATION_FLAGS | uint |
145145
| System.Reflection.ImageFileMachine | int |
146-
| System.Reflection.MdSigCallingConvention | int |
146+
| System.Reflection.MdSigCallingConvention | byte |
147147
| System.Reflection.MemberTypes | int |
148148
| System.Reflection.MetadataTokenType | int |
149149
| System.Reflection.MethodAttributes | int |
@@ -175,17 +175,17 @@
175175
| System.Runtime.InteropServices.ComMemberType | int |
176176
| System.Runtime.InteropServices.ComTypes.CALLCONV | int |
177177
| System.Runtime.InteropServices.ComTypes.DESCKIND | int |
178-
| System.Runtime.InteropServices.ComTypes.FUNCFLAGS | int |
178+
| System.Runtime.InteropServices.ComTypes.FUNCFLAGS | short |
179179
| System.Runtime.InteropServices.ComTypes.FUNCKIND | int |
180-
| System.Runtime.InteropServices.ComTypes.IDLFLAG | int |
180+
| System.Runtime.InteropServices.ComTypes.IDLFLAG | short |
181181
| System.Runtime.InteropServices.ComTypes.IMPLTYPEFLAGS | int |
182182
| System.Runtime.InteropServices.ComTypes.INVOKEKIND | int |
183-
| System.Runtime.InteropServices.ComTypes.LIBFLAGS | int |
184-
| System.Runtime.InteropServices.ComTypes.PARAMFLAG | int |
183+
| System.Runtime.InteropServices.ComTypes.LIBFLAGS | short |
184+
| System.Runtime.InteropServices.ComTypes.PARAMFLAG | short |
185185
| System.Runtime.InteropServices.ComTypes.SYSKIND | int |
186-
| System.Runtime.InteropServices.ComTypes.TYPEFLAGS | int |
186+
| System.Runtime.InteropServices.ComTypes.TYPEFLAGS | short |
187187
| System.Runtime.InteropServices.ComTypes.TYPEKIND | int |
188-
| System.Runtime.InteropServices.ComTypes.VARFLAGS | int |
188+
| System.Runtime.InteropServices.ComTypes.VARFLAGS | short |
189189
| System.Runtime.InteropServices.ComTypes.VARKIND | int |
190190
| System.Runtime.InteropServices.CustomQueryInterfaceMode | int |
191191
| System.Runtime.InteropServices.CustomQueryInterfaceResult | int |
@@ -194,7 +194,7 @@
194194
| System.Runtime.InteropServices.LayoutKind | int |
195195
| System.Runtime.InteropServices.UnmanagedType | int |
196196
| System.Runtime.InteropServices.VarEnum | int |
197-
| System.Runtime.Intrinsics.X86.FloatComparisonMode | int |
197+
| System.Runtime.Intrinsics.X86.FloatComparisonMode | byte |
198198
| System.Runtime.Loader.AssemblyLoadContext.InternalState | int |
199199
| System.Runtime.Serialization.StreamingContextStates | int |
200200
| System.RuntimeType.MemberListType | int |
@@ -203,7 +203,7 @@
203203
| System.Security.Permissions.PermissionState | int |
204204
| System.Security.Principal.PrincipalPolicy | int |
205205
| System.Security.SecurityCriticalScope | int |
206-
| System.Security.SecurityRuleSet | int |
206+
| System.Security.SecurityRuleSet | byte |
207207
| System.String.TrimType | int |
208208
| System.StringComparison | int |
209209
| System.StringSplitOptions | int |
@@ -217,9 +217,9 @@
217217
| System.Threading.LockRecursionPolicy | int |
218218
| System.Threading.ReaderWriterLockSlim.EnterLockType | int |
219219
| System.Threading.ReaderWriterLockSlim.EnterSpinLockReason | int |
220-
| System.Threading.ReaderWriterLockSlim.WaiterStates | int |
220+
| System.Threading.ReaderWriterLockSlim.WaiterStates | byte |
221221
| System.Threading.StackCrawlMark | int |
222-
| System.Threading.Tasks.ConcurrentExclusiveSchedulerPair.ProcessingMode | int |
222+
| System.Threading.Tasks.ConcurrentExclusiveSchedulerPair.ProcessingMode | byte |
223223
| System.Threading.Tasks.InternalTaskOptions | int |
224224
| System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags | int |
225225
| System.Threading.Tasks.Sources.ValueTaskSourceStatus | int |
@@ -231,7 +231,7 @@
231231
| System.Threading.ThreadState | int |
232232
| System.Threading.WaitHandle.OpenExistingResult | int |
233233
| System.TimeZoneInfo.StringSerializer.State | int |
234-
| System.TimeZoneInfo.TZVersion | int |
234+
| System.TimeZoneInfo.TZVersion | byte |
235235
| System.TimeZoneInfo.TimeZoneInfoResult | int |
236236
| System.TimeZoneInfoOptions | int |
237237
| System.TokenType | int |

0 commit comments

Comments
 (0)