Skip to content

Commit d5989b1

Browse files
atsushienojonpryor
authored andcommitted
[api-xml-adjuster] further fix on generic nested type name parsing. (#115)
We have fixed nested [generic type name crashes][1] at 769f944, but that was only to fix the crash. The resulting type name was not parsed correctly - namely, the resulting type name dropped the remainings after the first generic arguments list i.e. in `A<b>.C<d>`, `.C<d>` part had dropped. The cause of the problem is somewhat deep, as JavaTypeName and JavaTypeReference do not consider the possibility that both the nested generic parent and child have generic arguments. Anyhow in JavaTypeName now we store the expected information, by having (hacky) `GenericParent` property to store the expected information. Now it comes with a test so that it should prove the purpose of the change. [1]: https://bugzilla.xamarin.com/show_bug.cgi?id=46344
1 parent 39f1744 commit d5989b1

File tree

3 files changed

+66
-28
lines changed

3 files changed

+66
-28
lines changed

src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiTypeResolverExtensions.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ public static JavaTypeReference Parse (this JavaApi api, string name, params Jav
1818
var tn = JavaTypeName.Parse (name);
1919
return JavaTypeNameToReference (api, tn, contextTypeParameters);
2020
}
21-
21+
2222
static JavaTypeReference JavaTypeNameToReference (this JavaApi api, JavaTypeName tn, params JavaTypeParameters [] contextTypeParameters)
2323
{
24-
var tp = contextTypeParameters.Where (tps => tps != null).SelectMany (tps => tps.TypeParameters).FirstOrDefault (_ => _.Name == tn.FullNameNonGeneric);
24+
var tp = contextTypeParameters.Where (tps => tps != null).SelectMany (tps => tps.TypeParameters).FirstOrDefault (_ => _.Name == tn.DottedName);
2525
if (tp != null)
2626
return new JavaTypeReference (tp, tn.ArrayPart);
27-
if (tn.FullNameNonGeneric == JavaTypeReference.GenericWildcard.SpecialName)
27+
if (tn.DottedName == JavaTypeReference.GenericWildcard.SpecialName)
2828
return new JavaTypeReference (tn.BoundsType, tn.GenericConstraints?.Select (gc => JavaTypeNameToReference (api, gc, contextTypeParameters)), tn.ArrayPart);
29-
var primitive = JavaTypeReference.GetSpecialType (tn.FullNameNonGeneric);
29+
var primitive = JavaTypeReference.GetSpecialType (tn.DottedName);
3030
if (primitive != null)
3131
return tn.ArrayPart == null && tn.GenericConstraints == null ? primitive : new JavaTypeReference (primitive, tn.ArrayPart, tn.BoundsType, tn.GenericConstraints?.Select (gc => JavaTypeNameToReference (api, gc, contextTypeParameters)));
3232
var type = api.FindNonGenericType (tn.FullNameNonGeneric);

src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaTypeName.cs

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public class JavaTypeName
3333
public static JavaTypeName Parse (string dottedFullName)
3434
{
3535
var ret = new JavaTypeName ();
36-
36+
3737
foreach (var label in genericConstraintsLabels) {
3838
int gcidx = dottedFullName.IndexOf (label, StringComparison.Ordinal);
3939
int gcgidx = gcidx < 0 ? -1 : dottedFullName.IndexOf ('<', 0, gcidx);
@@ -45,7 +45,7 @@ public static JavaTypeName Parse (string dottedFullName)
4545
dottedFullName = dottedFullName.Substring (0, gcidx).Trim ();
4646
}
4747
}
48-
48+
4949
if (dottedFullName.EndsWith ("...", StringComparison.Ordinal)) {
5050
ret.ArrayPart = "...";
5151
dottedFullName = dottedFullName.Substring (0, dottedFullName.Length - 3);
@@ -56,36 +56,47 @@ public static JavaTypeName Parse (string dottedFullName)
5656
dottedFullName = dottedFullName.Substring (0, aidx);
5757
}
5858

59-
Func<string, int, int> getMatchingGenericCloser = (str, start) => {
60-
int count = 0;
61-
for (int i = start; i < str.Length; i++) {
62-
switch (str [i]) {
63-
case '<':
64-
count++;
65-
break;
66-
case '>':
67-
if (count-- == 0)
68-
return i;
69-
break;
70-
}
71-
}
72-
return -1;
73-
};
7459
int idx = dottedFullName.IndexOf ('<');
60+
int nextIndex = dottedFullName.Length;
7561
if (idx > 0) {
76-
int last = getMatchingGenericCloser (dottedFullName, idx + 1);
62+
int last = GetMatchingGenericCloser (dottedFullName, idx + 1);
7763
ret.GenericArguments = ParseCommaSeparatedTypeNames (dottedFullName.Substring (idx + 1, last - idx - 1))
7864
.Select (s => JavaTypeName.Parse (s.Trim ()))
7965
.ToArray ();
80-
dottedFullName = dottedFullName.Substring (0, idx);
66+
nextIndex = last + 1;
8167
}
82-
8368
// at this state, there is no way to distinguish package name from this name specification.
84-
ret.FullNameNonGeneric = dottedFullName;
85-
69+
ret.DottedName = idx < 0 ? dottedFullName : dottedFullName.Substring (0, idx);
70+
71+
if (nextIndex < dottedFullName.Length) {
72+
if (dottedFullName [nextIndex] != '.')
73+
throw new ArgumentException (nameof (dottedFullName));
74+
// the generic parent is parsed, but the rest is still there.
75+
var parent = ret;
76+
ret = Parse (dottedFullName.Substring (nextIndex + 1));
77+
ret.GenericParent = parent;
78+
}
79+
8680
return ret;
8781
}
8882

83+
static int GetMatchingGenericCloser (string str, int start)
84+
{
85+
int count = 0;
86+
for (int i = start; i < str.Length; i++) {
87+
switch (str [i]) {
88+
case '<':
89+
count++;
90+
break;
91+
case '>':
92+
if (count-- == 0)
93+
return i;
94+
break;
95+
}
96+
}
97+
return -1;
98+
}
99+
89100
static IEnumerable<string> ParseCommaSeparatedTypeNames (string args)
90101
{
91102
int comma = args.IndexOf (',');
@@ -119,11 +130,22 @@ static IEnumerable<string> ParseCommaSeparatedTypeNames (string args)
119130
}
120131
}
121132
}
122-
123-
public string FullNameNonGeneric { get; set; }
133+
134+
public JavaTypeName GenericParent { get; set; }
135+
public string DottedName { get; set; }
124136
public string BoundsType { get; set; } // " extends " / " super "
125137
public IList<JavaTypeName> GenericConstraints { get; private set; }
126138
public IList<JavaTypeName> GenericArguments { get; private set; }
127139
public string ArrayPart { get; set; }
140+
141+
public string FullNameNonGeneric {
142+
get {
143+
if (GenericParent != null)
144+
return GenericParent.FullNameNonGeneric + "." + DottedName;
145+
else
146+
return DottedName;
147+
}
148+
}
149+
128150
}
129151
}

src/Xamarin.Android.Tools.ApiXmlAdjuster/Tests/JavaApiTest.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,22 @@ public void ParseName ()
4242
Assert.AreEqual (1, ga2.GenericConstraints.Count, "genarg#1 incorrect number of parsed generic constraints");
4343
Assert.AreEqual ("U", ga2.GenericConstraints [0].FullNameNonGeneric, "genarg#1.1 constraint name mismatch");
4444
}
45+
46+
[Test]
47+
public void ParseName2 ()
48+
{
49+
string name = "com.good.gd.ndkproxy.auth.GDFingerprintAuthenticationManager.a<com.good.gd.ndkproxy.auth.c.a>.b<com.good.gd.ndkproxy.auth.d.a>";
50+
var tn = JavaTypeName.Parse (name);
51+
Assert.IsTrue (tn.GenericParent != null, "result has generic parent");
52+
Assert.AreEqual ("b", tn.DottedName, "result name mismatch");
53+
Assert.AreEqual ("com.good.gd.ndkproxy.auth.GDFingerprintAuthenticationManager.a.b", tn.FullNameNonGeneric, "failed to parse name");
54+
Assert.AreEqual (1, tn.GenericArguments.Count, "result genparams count mismatch");
55+
Assert.AreEqual ("com.good.gd.ndkproxy.auth.d.a", tn.GenericArguments [0].FullNameNonGeneric, "result genarg name mismatch");
56+
var p = tn.GenericParent;
57+
Assert.AreEqual (1, p.GenericArguments.Count, "top genparams count");
58+
var ga1 = p.GenericArguments [0];
59+
Assert.AreEqual ("com.good.gd.ndkproxy.auth.c.a", ga1.FullNameNonGeneric, "top genarg name mismatch");
60+
}
4561
}
4662
}
4763

0 commit comments

Comments
 (0)