Skip to content
This repository was archived by the owner on Jul 6, 2026. It is now read-only.

Commit 5009f32

Browse files
jpobstjonpryor
authored andcommitted
[generator] Improve generic type lookup (#552)
Fixes: #543 In commit 262743b we began stripping the arity from Cecil imported types so that we wouldn't write invalid types like ``System.Collections.Generic.IList`1<string>``, in order to correctly emit `System.Collections.Generic.IList<string>`. However when we try to resolve these types in the `SymbolTable` we only look at the type name, ignoring the generic type parameters. In this case we are looking for `System.Collections.Generic.IList` but the type is stored in the symbol table with the arity to disambiguate types like ``Action`1`` and ``Action`2``. Therefore our lookup fails because the table key is ``System.Collections.Generic.IList`1``. For example, if we have `LibraryA.dll` with: public class Foo : Java.Lang.Object { public virtual void Bar (IList<string> p0) {…} } And we attempt to bind a `LibraryB.jar` which references `LibraryA.dll`, overriding `Foo.Bar()`: public class Foo2 : Foo { public override void Bar (IList<string> p0) {…} } Then `Foo2.Bar()` would elicit a BG8800 warning: warning BG8800: Unknown parameter type System.Collections.Generic.IList<System.String> in method Bar in managed type Foo2. Fix type lookup so that if the type is not found in the `SymbolTable` and there are generic type parameters, calculate the arity from the generic type parameters and look in the table again. That is, `System.Collections.Generic.IList<string>` is rechecked as ``System.Collections.Generic.IList`1``, which allows the type to be found.
1 parent 3bf5333 commit 5009f32

2 files changed

Lines changed: 75 additions & 2 deletions

File tree

‎tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/SymbolTable.cs‎

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,15 @@ public ISymbol Lookup (string java_type)
260260
if(all_symbols_cache==null)
261261
all_symbols_cache=newConcurrentDictionary<string,ISymbol>(symbols.Values.SelectMany(v =>v).GroupBy(s =>s.FullName).ToDictionary(s =>s.Key, s =>s.FirstOrDefault()));
262262

263-
all_symbols_cache.TryGetValue(key,outsym);
263+
if(!all_symbols_cache.TryGetValue(key,outsym)){
264+
// We may be looking for a type like:
265+
// - System.Collections.Generic.IList<Java.Util.Locale.LanguageRange>
266+
// Our key is "System.Collections.Generic.IList", but it's stored in
267+
// the symbol table with the arity so we need to look for
268+
// "System.Collections.Generic.IList`1" to find a match
269+
key=AddArity(key,type_params);
270+
all_symbols_cache.TryGetValue(key,outsym);
271+
}
264272
}
265273
}
266274
ISymbolresult;
@@ -290,7 +298,32 @@ public ISymbol Lookup (string java_type)
290298

291299
returnresult;
292300
}
293-
301+
302+
privatestringAddArity(stringkey,stringtypeParams)
303+
{
304+
if(string.IsNullOrWhiteSpace(typeParams)||!typeParams.StartsWith("<")||!typeParams.EndsWith(">"))
305+
returnkey;
306+
307+
varnested_count=0;
308+
vararity=1;
309+
310+
// Remove the outer <>
311+
typeParams=typeParams.Substring(1,typeParams.Length-2);
312+
313+
foreach(varcintypeParams){
314+
if(c=='>')
315+
nested_count--;
316+
317+
if(c=='<')
318+
nested_count++;
319+
320+
if(nested_count==0&&c==',')
321+
arity++;
322+
}
323+
324+
return$"{key}`{arity}";
325+
}
326+
294327
publicvoidDump()
295328
{
296329
foreach(varpinsymbols){
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
usingSystem;
2+
usingMonoDroid.Generation;
3+
usingNUnit.Framework;
4+
5+
namespacegeneratortests
6+
{
7+
[TestFixture]
8+
publicclassSymbolTableTests
9+
{
10+
[Test]
11+
publicvoidFindGenericTypes()
12+
{
13+
vartable=newSymbolTable();
14+
15+
varlist=newInterfaceGen(newGenBaseSupport{
16+
Name="System.Collections.Generic.IList`1",
17+
FullName="System.Collections.Generic.IList`1",
18+
JavaSimpleName="System.Collections.Generic.IList`1"
19+
});
20+
21+
table.AddType(list);
22+
23+
vardict=newInterfaceGen(newGenBaseSupport{
24+
Name="System.Collections.Generic.IDictionary`2",
25+
FullName="System.Collections.Generic.IDictionary`2",
26+
JavaSimpleName="System.Collections.Generic.IDictionary`2"
27+
});
28+
29+
table.AddType(dict);
30+
31+
Assert.AreEqual("System.Collections.Generic.IList`1",table.Lookup("System.Collections.Generic.IList<Java.Util.Locale.LanguageRange>").FullName);
32+
Assert.AreEqual("System.Collections.Generic.IList`1",table.Lookup("System.Collections.Generic.IList<List<Java.Util.Locale.LanguageRange>>").FullName);
33+
34+
Assert.AreEqual("System.Collections.Generic.IDictionary`2",table.Lookup("System.Collections.Generic.IDictionary<string, Java.Util.Locale.LanguageRange>").FullName);
35+
Assert.AreEqual("System.Collections.Generic.IDictionary`2",table.Lookup("System.Collections.Generic.IDictionary<string, List<Java.Util.Locale.LanguageRange>>").FullName);
36+
37+
Assert.AreEqual("System.Collections.Generic.IList`1",table.Lookup("System.Collections.Generic.IList<Dictionary<string, Java.Util.Locale.LanguageRange>>").FullName);
38+
}
39+
}
40+
}

0 commit comments

Comments
 (0)