Skip to content

Commit 73be9ed

Browse files
authored
Improve crawling of member refs and generics instances to fill TypeSpec table (#187)
***NO_CI***
1 parent 577c971 commit 73be9ed

File tree

1 file changed

+180
-24
lines changed

1 file changed

+180
-24
lines changed

MetadataProcessor.Shared/Tables/nanoTypeSpecificationsTable.cs

Lines changed: 180 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ public nanoTypeSpecificationsTable(
100100

101101
_idByTypeSpecifications = new Dictionary<TypeReference, ushort>(new TypeReferenceEqualityComparer(context));
102102

103+
AddTypeLevelGenericParameters();
103104
FillTypeSpecsFromTypes();
104-
105105
FillTypeSpecsFromMemberReferences();
106106
}
107107

@@ -124,14 +124,52 @@ public bool TryGetTypeReferenceId(
124124

125125
return false;
126126
}
127-
128127
public TypeReference TryGetTypeSpecification(MetadataToken token)
129128
{
130-
return _idByTypeSpecifications.FirstOrDefault(typeEntry => typeEntry.Key.MetadataToken == token).Key;
129+
// try a direct match on the TypeReference itself
130+
TypeReference direct = _idByTypeSpecifications.Keys.FirstOrDefault(t => t.MetadataToken == token);
131+
132+
if (direct != null)
133+
{
134+
return direct;
135+
}
136+
137+
// Look among the generic-instances already seeded
138+
GenericInstanceType genericInst = _idByTypeSpecifications.Keys
139+
.OfType<GenericInstanceType>()
140+
.FirstOrDefault(git => git.ElementType.MetadataToken == token);
141+
142+
if (genericInst != null)
143+
{
144+
return genericInst;
145+
}
146+
147+
// maybe this instanced type is in TypeReferencesTable
148+
GenericInstanceType external = _context.TypeReferencesTable.Items
149+
.OfType<GenericInstanceType>()
150+
.FirstOrDefault(git => git.ElementType.MetadataToken == token);
151+
152+
if (external != null)
153+
{
154+
// seed it now so future lookups find it immediately
155+
ushort sigId = _context.SignaturesTable.GetOrCreateSignatureId(external);
156+
157+
AddIfNew(external, sigId);
158+
159+
// and pull in its nested specs (generic arguments, element types, etc.)
160+
ExpandNestedTypeSpecs(external);
161+
162+
return external;
163+
}
164+
165+
// some edge case not being handled...
166+
// default to null
167+
return null;
131168
}
132169

170+
133171
/// <summary>
134-
/// Tries to find type reference by the index on the TypeSpec list.
172+
/// Tries to find type reference by the index on the <see cref="TypeSpec"/> list.
135173
/// </summary>
136174
/// <param name="index">Index of the type reference in the list.</param>
137175
/// <returns>Returns the type reference if found, otherwise returns <c>null</c>.</returns>
@@ -197,44 +235,162 @@ private void FillTypeSpecsFromMemberReferences()
197235
}
198236
}
199237
}
238+
239+
// make sure we pick up *all* GenericInstanceType entries
240+
// that may have come in via the TypeReferencesTable.
241+
foreach (GenericInstanceType genericInstanceType in _context.TypeReferencesTable.Items.OfType<GenericInstanceType>())
242+
{
243+
if (!_idByTypeSpecifications.ContainsKey(genericInstanceType))
244+
{
245+
// create or get the signature ID for this instanced type
246+
ushort sigId = _context.SignaturesTable.GetOrCreateSignatureId(genericInstanceType);
247+
_idByTypeSpecifications.Add(genericInstanceType, sigId);
248+
249+
// (and don’t forget to pull in any nested generic-parameter args)
250+
foreach (GenericParameter arg in genericInstanceType.GenericArguments.OfType<GenericParameter>())
251+
{
252+
if (!_idByTypeSpecifications.ContainsKey(arg))
253+
{
254+
ushort argSig = _context.SignaturesTable.GetOrCreateSignatureId(arg);
255+
_idByTypeSpecifications.Add(arg, argSig);
256+
}
257+
}
258+
}
259+
}
200260
}
201261

202262
private void FillTypeSpecsFromTypes()
203263
{
204-
foreach (TypeDefinition t in _context.TypeDefinitionTable.Items)
264+
foreach (TypeDefinition td in _context.TypeDefinitionTable.Items)
205265
{
206-
foreach (MethodDefinition m in t.Methods.Where(method => method.HasBody))
266+
foreach (MethodDefinition m in td.Methods.Where(m => m.HasBody))
207267
{
208-
foreach (Instruction instruction in m.Body.Instructions)
268+
foreach (Instruction instr in m.Body.Instructions)
209269
{
210-
if (instruction.Operand is GenericParameter genericParameter)
270+
if (instr.Operand is GenericParameter gp)
211271
{
212-
ushort signatureId = _context.SignaturesTable.GetOrCreateSignatureId(genericParameter);
213-
214-
if (!_idByTypeSpecifications.ContainsKey(genericParameter))
215-
{
216-
_idByTypeSpecifications.Add(genericParameter, signatureId);
217-
}
272+
AddIfNew(gp, _context.SignaturesTable.GetOrCreateSignatureId(gp));
218273
}
219-
else if (instruction.Operand is TypeReference typeReference)
274+
else if (instr.Operand is TypeReference tr)
220275
{
221-
// Optional: Check additional conditions if needed,
222-
// for example, if the operand type should be an array.
223-
if (instruction.OpCode.OperandType == OperandType.InlineType && !typeReference.IsArray)
276+
// refuse multi-dimensional arrays
277+
// we only support jagged arrays
278+
if (tr.IsArray)
224279
{
225-
continue;
280+
var at = (ArrayType)tr;
281+
282+
if (at.Rank > 1)
283+
{
284+
throw new ArgumentException(
285+
$".NET nanoFramework only supports jagged arrays: {tr.FullName}");
286+
}
226287
}
227288

228-
ushort signatureId = _context.SignaturesTable.GetOrCreateSignatureId(typeReference);
289+
// register the type reference itself...
290+
ushort sigId = _context.SignaturesTable.GetOrCreateSignatureId(tr);
291+
AddIfNew(tr, sigId);
229292

230-
if (!_idByTypeSpecifications.ContainsKey(typeReference))
231-
{
232-
_idByTypeSpecifications.Add(typeReference, signatureId);
233-
}
293+
// ... then walk *into* any nested TypeSpecifications it might contain
294+
ExpandNestedTypeSpecs(tr);
234295
}
235296
}
236297
}
237298
}
238299
}
300+
301+
/// <summary>
302+
/// Recursively finds any TypeSpecification bits of 't' and adds them
303+
/// (element types, generic arguments, declaring types, by/ref, pointers, etc.)
304+
/// </summary>
305+
private void ExpandNestedTypeSpecs(TypeReference t)
306+
{
307+
if (!(t is TypeSpecification ts))
308+
{
309+
return;
310+
}
311+
312+
// element type of pointers, by-refs, modifiers, arrays, & generic definitions
313+
TypeReference inner = null;
314+
switch (ts)
315+
{
316+
case GenericInstanceType git:
317+
inner = git.ElementType;
318+
foreach (var arg in git.GenericArguments)
319+
ExpandNestedTypeSpecs(arg);
320+
break;
321+
322+
case ArrayType at:
323+
inner = at.ElementType;
324+
break;
325+
326+
case ByReferenceType br:
327+
inner = br.ElementType;
328+
break;
329+
330+
case PointerType pt:
331+
inner = pt.ElementType;
332+
break;
333+
334+
case OptionalModifierType om:
335+
inner = om.ElementType;
336+
break;
337+
338+
case RequiredModifierType rm:
339+
inner = rm.ElementType;
340+
break;
341+
}
342+
343+
if (inner != null)
344+
{
345+
ushort innerId = _context.SignaturesTable.GetOrCreateSignatureId(inner);
346+
AddIfNew(inner, innerId);
347+
ExpandNestedTypeSpecs(inner);
348+
}
349+
350+
// nested/declaring types
351+
if (ts.DeclaringType != null)
352+
{
353+
TypeReference decl = ts.DeclaringType;
354+
ushort declId = _context.SignaturesTable.GetOrCreateSignatureId(decl);
355+
AddIfNew(decl, declId);
356+
ExpandNestedTypeSpecs(decl);
357+
}
358+
}
359+
360+
/// <summary>
361+
/// Helper to add to `_idByTypeSpecifications` only if we haven’t already seen it
362+
/// </summary>
363+
private void AddIfNew(
364+
TypeReference tr,
365+
ushort sigId)
366+
{
367+
if (!_idByTypeSpecifications.ContainsKey(tr))
368+
{
369+
_idByTypeSpecifications.Add(tr, sigId);
370+
}
371+
}
372+
373+
private void AddTypeLevelGenericParameters()
374+
{
375+
foreach (TypeDefinition td in _context.TypeDefinitionTable.Items.Where(t => t.HasGenericParameters))
376+
{
377+
// register each generic parameter (T)
378+
foreach (GenericParameter gp in td.GenericParameters)
379+
{
380+
ushort gpSig = _context.SignaturesTable.GetOrCreateSignatureId(gp);
381+
AddIfNew(gp, gpSig);
382+
}
383+
384+
// seed the *open* GenericInstanceType (e.g. Action`1<T>)
385+
var openGeneric = new GenericInstanceType(td);
386+
foreach (GenericParameter gp in td.GenericParameters)
387+
{
388+
openGeneric.GenericArguments.Add(gp);
389+
}
390+
391+
ushort openSig = _context.SignaturesTable.GetOrCreateSignatureId(openGeneric);
392+
AddIfNew(openGeneric, openSig);
393+
}
394+
}
239395
}
240396
}

0 commit comments

Comments
 (0)