Skip to content

Commit 3ea14be

Browse files
[typemap] Defer complex super arguments to javac
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 807c022 commit 3ea14be

4 files changed

Lines changed: 33 additions & 188 deletions

File tree

src/Microsoft.Android.Sdk.TrimmableTypeMap/Scanner/JavaPeerScanner.cs

Lines changed: 6 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -3024,17 +3024,8 @@ bool IsActivationFrameworkType (TypeRefData type, string managedTypeName, string
30243024
static bool HasValidSuperArgumentReferences (string superArgumentsString, int parameterCount)
30253025
{
30263026
var tokens = TokenizeJavaExpression (superArgumentsString);
3027-
var lambdaDeclarations = new HashSet<int> ();
3028-
var lambdaScopes = new List<(string Name, int Start, int End)> ();
3029-
for (int i = 0; i < tokens.Count; i++) {
3030-
if (tokens [i].Text != "->") {
3031-
continue;
3032-
}
3033-
int scopeEnd = FindLambdaBodyEnd (tokens, i + 1, superArgumentsString.Length);
3034-
foreach (int declaration in GetLambdaParameterDeclarations (tokens, i)) {
3035-
lambdaDeclarations.Add (declaration);
3036-
lambdaScopes.Add ((tokens [declaration].Text, tokens [i].End, scopeEnd));
3037-
}
3027+
if (tokens.Any (token => token.Text is "->" or "::")) {
3028+
return true;
30383029
}
30393030

30403031
for (int i = 0; i < tokens.Count; i++) {
@@ -3043,10 +3034,7 @@ static bool HasValidSuperArgumentReferences (string superArgumentsString, int pa
30433034
token.Text.Skip (1).Any (c => !char.IsDigit (c))) {
30443035
continue;
30453036
}
3046-
if (lambdaDeclarations.Contains (i) ||
3047-
lambdaScopes.Any (scope => scope.Name == token.Text && token.Start >= scope.Start && token.Start < scope.End) ||
3048-
(i > 0 && tokens [i - 1].Text == ".") ||
3049-
IsMethodReferenceName (tokens, i)) {
3037+
if (i > 0 && tokens [i - 1].Text == ".") {
30503038
continue;
30513039
}
30523040

@@ -3060,7 +3048,7 @@ static bool HasValidSuperArgumentReferences (string superArgumentsString, int pa
30603048
return true;
30613049
}
30623050

3063-
readonly record struct JavaLexicalToken (string Text, int Start, int End, bool IsIdentifier);
3051+
readonly record struct JavaLexicalToken (string Text, bool IsIdentifier);
30643052

30653053
static List<JavaLexicalToken> TokenizeJavaExpression (string value)
30663054
{
@@ -3095,125 +3083,17 @@ static List<JavaLexicalToken> TokenizeJavaExpression (string value)
30953083
while (i < value.Length && IsJavaIdentifierCharacter (value [i])) {
30963084
i++;
30973085
}
3098-
tokens.Add (new JavaLexicalToken (value.Substring (start, i - start), start, i, IsIdentifier: true));
3086+
tokens.Add (new JavaLexicalToken (value.Substring (start, i - start), IsIdentifier: true));
30993087
continue;
31003088
}
31013089
int symbolLength = i + 1 < value.Length &&
31023090
((value [i] == '-' && value [i + 1] == '>') || (value [i] == ':' && value [i + 1] == ':')) ? 2 : 1;
3103-
tokens.Add (new JavaLexicalToken (value.Substring (i, symbolLength), i, i + symbolLength, IsIdentifier: false));
3091+
tokens.Add (new JavaLexicalToken (value.Substring (i, symbolLength), IsIdentifier: false));
31043092
i += symbolLength;
31053093
}
31063094
return tokens;
31073095
}
31083096

3109-
static List<int> GetLambdaParameterDeclarations (IReadOnlyList<JavaLexicalToken> tokens, int arrow)
3110-
{
3111-
if (arrow == 0) {
3112-
return [];
3113-
}
3114-
if (tokens [arrow - 1].IsIdentifier) {
3115-
return [arrow - 1];
3116-
}
3117-
if (tokens [arrow - 1].Text != ")") {
3118-
return [];
3119-
}
3120-
int open = FindMatchingOpenToken (tokens, arrow - 1, "(", ")");
3121-
if (open < 0) {
3122-
return [];
3123-
}
3124-
3125-
var declarations = new List<int> ();
3126-
int segmentStart = open + 1;
3127-
int angleDepth = 0;
3128-
for (int i = segmentStart; i <= arrow - 1; i++) {
3129-
string text = tokens [i].Text;
3130-
if (text == "<") {
3131-
angleDepth++;
3132-
} else if (text == ">" && angleDepth > 0) {
3133-
angleDepth--;
3134-
}
3135-
if ((text == "," && angleDepth == 0) || i == arrow - 1) {
3136-
int segmentEnd = text == "," ? i : arrow - 1;
3137-
for (int j = segmentEnd - 1; j >= segmentStart; j--) {
3138-
if (tokens [j].IsIdentifier) {
3139-
declarations.Add (j);
3140-
break;
3141-
}
3142-
}
3143-
segmentStart = i + 1;
3144-
}
3145-
}
3146-
return declarations;
3147-
}
3148-
3149-
static int FindLambdaBodyEnd (IReadOnlyList<JavaLexicalToken> tokens, int start, int valueLength)
3150-
{
3151-
int parentheses = 0, brackets = 0, braces = 0, genericArguments = 0;
3152-
for (int i = start; i < tokens.Count; i++) {
3153-
string text = tokens [i].Text;
3154-
if (text == "<" && (genericArguments > 0 || IsGenericArgumentOpen (tokens, i))) {
3155-
genericArguments++;
3156-
} else if (text == ">" && genericArguments > 0) {
3157-
genericArguments--;
3158-
}
3159-
if (text == "," && parentheses == 0 && brackets == 0 && braces == 0 && genericArguments == 0) {
3160-
return tokens [i].Start;
3161-
}
3162-
if (genericArguments == 0 &&
3163-
((text == ")" && parentheses == 0) || (text == "]" && brackets == 0) || (text == "}" && braces == 0))) {
3164-
return tokens [i].Start;
3165-
}
3166-
parentheses += text == "(" ? 1 : text == ")" ? -1 : 0;
3167-
brackets += text == "[" ? 1 : text == "]" ? -1 : 0;
3168-
braces += text == "{" ? 1 : text == "}" ? -1 : 0;
3169-
}
3170-
return valueLength;
3171-
}
3172-
3173-
static bool IsGenericArgumentOpen (IReadOnlyList<JavaLexicalToken> tokens, int open)
3174-
{
3175-
int depth = 0;
3176-
for (int i = open; i < tokens.Count; i++) {
3177-
if (tokens [i].Text == "<") {
3178-
depth++;
3179-
} else if (tokens [i].Text == ">" && --depth == 0) {
3180-
if (i + 1 >= tokens.Count) {
3181-
return false;
3182-
}
3183-
string following = tokens [i + 1].Text;
3184-
return following is "(" or "[" or "." or "::" ||
3185-
(tokens [i + 1].IsIdentifier && open > 0 && tokens [open - 1].Text is "." or "::");
3186-
}
3187-
}
3188-
return false;
3189-
}
3190-
3191-
static int FindMatchingOpenToken (IReadOnlyList<JavaLexicalToken> tokens, int close, string openText, string closeText)
3192-
{
3193-
int depth = 0;
3194-
for (int i = close; i >= 0; i--) {
3195-
if (tokens [i].Text == closeText) {
3196-
depth++;
3197-
} else if (tokens [i].Text == openText && --depth == 0) {
3198-
return i;
3199-
}
3200-
}
3201-
return -1;
3202-
}
3203-
3204-
static bool IsMethodReferenceName (IReadOnlyList<JavaLexicalToken> tokens, int identifier)
3205-
{
3206-
int previous = identifier - 1;
3207-
if (previous >= 0 && tokens [previous].Text == "::") {
3208-
return true;
3209-
}
3210-
if (previous < 0 || tokens [previous].Text != ">") {
3211-
return false;
3212-
}
3213-
int open = FindMatchingOpenToken (tokens, previous, "<", ">");
3214-
return open > 0 && tokens [open - 1].Text == "::";
3215-
}
3216-
32173097
static bool IsJavaIdentifierCharacter (char value) =>
32183098
char.IsLetterOrDigit (value) || value == '_' || value == '$';
32193099

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/TrimmableTypeMapBuildTests.cs

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -732,27 +732,24 @@ public IntBase (int value) {}
732732
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "nested-generic", "success")]
733733
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "nested-generic", "success")]
734734
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "nested-generic", "success")]
735+
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "instanceof-generic", "success")]
736+
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "instanceof-generic", "success")]
737+
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "instanceof-generic", "success")]
735738
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "comparison", "success")]
736739
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "comparison", "success")]
737740
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "comparison", "success")]
738741
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "shift", "success")]
739742
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "shift", "success")]
740743
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "shift", "success")]
741-
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "invalid-bare", "JAVAC0000")]
742-
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "invalid-bare", "XA4262")]
743-
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "invalid-bare", "XA4262")]
744-
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "invalid-parenthesized-bare", "JAVAC0000")]
745-
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "invalid-parenthesized-bare", "XA4262")]
746-
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "invalid-parenthesized-bare", "XA4262")]
747-
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "invalid-generic-reference-bare", "JAVAC0000")]
748-
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "invalid-generic-reference-bare", "XA4262")]
749-
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "invalid-generic-reference-bare", "XA4262")]
750-
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "invalid-generic-construction-bare", "JAVAC0000")]
751-
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "invalid-generic-construction-bare", "XA4262")]
752-
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "invalid-generic-construction-bare", "XA4262")]
753-
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "invalid-comparison-bare", "JAVAC0000")]
754-
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "invalid-comparison-bare", "XA4262")]
755-
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "invalid-comparison-bare", "XA4262")]
744+
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "ordinary-bare", "JAVAC0000")]
745+
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "ordinary-bare", "XA4262")]
746+
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "ordinary-bare", "XA4262")]
747+
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "ordinary-call", "JAVAC0000")]
748+
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "ordinary-call", "XA4262")]
749+
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "ordinary-call", "XA4262")]
750+
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "ordinary-arithmetic", "JAVAC0000")]
751+
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "ordinary-arithmetic", "XA4262")]
752+
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "ordinary-arithmetic", "XA4262")]
756753
public void Build_SuperArgumentsLambdaAndMethodReference_MatchJavac (
757754
string typeMapImplementation,
758755
AndroidRuntime runtime,
@@ -773,19 +770,19 @@ public void Build_SuperArgumentsLambdaAndMethodReference_MatchJavac (
773770
"generic-method-reference" => "Helper::<String>p1",
774771
"generic-construction" => "(p1) -> new SimpleEntry<String, String>(p1, p1)",
775772
"nested-generic" => "(p1) -> new SimpleEntry<String, java.util.List<String>>(p1, java.util.Arrays.asList(\\\"a,b\\\", p1))",
773+
"instanceof-generic" => "(p1) -> p1 instanceof java.util.Map<?, ?> ? p1 : p1",
776774
"comparison" => "(int p1) -> p1 < 2 ? p1 : 2",
777775
"shift" => "(int p1) -> p1 >> 1",
778-
"invalid-bare" => "p1 -> p1, p1",
779-
"invalid-parenthesized-bare" => "(p1) -> p1, p1",
780-
"invalid-generic-reference-bare" => "Helper::<String>p1, p1",
781-
"invalid-generic-construction-bare" => "(p1) -> new SimpleEntry<String, String>(p1, p1), p1",
782-
"invalid-comparison-bare" => "(int p1) -> p1 < 2 ? p1 : 2, p1",
776+
"ordinary-bare" => "p1",
777+
"ordinary-call" => "p1.hashCode()",
778+
"ordinary-arithmetic" => "p1 + 1",
783779
_ => throw new InvalidOperationException ($"Unknown super argument shape '{shape}'."),
784780
};
785781
var functionalType = shape switch {
786782
"typed-lambda" => "java.util.function.BiFunction<String, String, String>",
787-
"comparison" or "shift" or "invalid-comparison-bare" => "java.util.function.IntUnaryOperator",
788-
"method-reference" or "generic-method-reference" or "invalid-generic-reference-bare" => "java.util.function.Supplier<String>",
783+
"comparison" or "shift" => "java.util.function.IntUnaryOperator",
784+
"instanceof-generic" => "java.util.function.Function<Object, ?>",
785+
"method-reference" or "generic-method-reference" => "java.util.function.Supplier<String>",
789786
_ => "java.util.function.Function<String, ?>",
790787
};
791788
var proj = new XamarinAndroidApplicationProject {

tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/InvalidConstructorFixtures/InvalidConstructors.cs

Lines changed: 7 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,13 @@ public class NestedGenericLambdaSuperArgumentsActivity : Android.App.Activity
403403
public NestedGenericLambdaSuperArgumentsActivity () { }
404404
}
405405

406+
[Register ("my/app/InstanceOfGenericLambdaSuperArgumentsActivity")]
407+
public class InstanceOfGenericLambdaSuperArgumentsActivity : Android.App.Activity
408+
{
409+
[Java.Interop.Export (".ctor", SuperArgumentsString = "(p1) -> p1 instanceof java.util.Map<?, ?> ? p1 : p1")]
410+
public InstanceOfGenericLambdaSuperArgumentsActivity () { }
411+
}
412+
406413
[Register ("my/app/ComparisonLambdaSuperArgumentsActivity")]
407414
public class ComparisonLambdaSuperArgumentsActivity : Android.App.Activity
408415
{
@@ -431,41 +438,6 @@ public class GenericMethodReferenceSuperArgumentsActivity : Android.App.Activity
431438
public GenericMethodReferenceSuperArgumentsActivity () { }
432439
}
433440

434-
[Register ("my/app/LambdaWithBareParameterActivity")]
435-
public class LambdaWithBareParameterActivity : Android.App.Activity
436-
{
437-
[Java.Interop.Export (".ctor", SuperArgumentsString = "p1 -> p1, p1")]
438-
public LambdaWithBareParameterActivity () { }
439-
}
440-
441-
[Register ("my/app/ParenthesizedLambdaWithBareParameterActivity")]
442-
public class ParenthesizedLambdaWithBareParameterActivity : Android.App.Activity
443-
{
444-
[Java.Interop.Export (".ctor", SuperArgumentsString = "(p1) -> p1, p1")]
445-
public ParenthesizedLambdaWithBareParameterActivity () { }
446-
}
447-
448-
[Register ("my/app/GenericMethodReferenceWithBareParameterActivity")]
449-
public class GenericMethodReferenceWithBareParameterActivity : Android.App.Activity
450-
{
451-
[Java.Interop.Export (".ctor", SuperArgumentsString = "Helper::<String>p1, p1")]
452-
public GenericMethodReferenceWithBareParameterActivity () { }
453-
}
454-
455-
[Register ("my/app/GenericConstructionWithBareParameterActivity")]
456-
public class GenericConstructionWithBareParameterActivity : Android.App.Activity
457-
{
458-
[Java.Interop.Export (".ctor", SuperArgumentsString = "(p1) -> new SimpleEntry<String, String>(p1, p1), p1")]
459-
public GenericConstructionWithBareParameterActivity () { }
460-
}
461-
462-
[Register ("my/app/ComparisonWithBareParameterActivity")]
463-
public class ComparisonWithBareParameterActivity : Android.App.Activity
464-
{
465-
[Java.Interop.Export (".ctor", SuperArgumentsString = "(int p1) -> p1 < 2 ? p1 : 2, p1")]
466-
public ComparisonWithBareParameterActivity () { }
467-
}
468-
469441
[Register ("my/app/ExportMappedCtorActivity")]
470442
public class ExportMappedCtorActivity : Android.App.Activity
471443
{

tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Scanner/ConstructorDetectionTests.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -246,11 +246,6 @@ public void ExportWithoutSuperArgumentsString_MissingBaseConstructor_IsDiagnosed
246246
[InlineData ("MyApp.InvalidSuperArgumentsActivity", "p1")]
247247
[InlineData ("MyApp.NonCanonicalSuperArgumentZeroActivity", "p00")]
248248
[InlineData ("MyApp.NonCanonicalSuperArgumentOneActivity", "p01")]
249-
[InlineData ("MyApp.LambdaWithBareParameterActivity", "p1 -> p1, p1")]
250-
[InlineData ("MyApp.ParenthesizedLambdaWithBareParameterActivity", "(p1) -> p1, p1")]
251-
[InlineData ("MyApp.GenericMethodReferenceWithBareParameterActivity", "Helper::<String>p1, p1")]
252-
[InlineData ("MyApp.GenericConstructionWithBareParameterActivity", "(p1) -> new SimpleEntry<String, String>(p1, p1), p1")]
253-
[InlineData ("MyApp.ComparisonWithBareParameterActivity", "(int p1) -> p1 < 2 ? p1 : 2, p1")]
254249
public void InvalidSuperArgumentsString_IsDiagnosed (string managedTypeName, string superArgumentsString)
255250
{
256251
var diagnostic = Assert.Single (ScanConstructorDiagnostics (managedTypeName));
@@ -278,6 +273,7 @@ public void InvalidSuperArgumentsString_IsDiagnosed (string managedTypeName, str
278273
[InlineData ("MyApp.LiteralCommaLambdaSuperArgumentsActivity")]
279274
[InlineData ("MyApp.GenericConstructionLambdaSuperArgumentsActivity")]
280275
[InlineData ("MyApp.NestedGenericLambdaSuperArgumentsActivity")]
276+
[InlineData ("MyApp.InstanceOfGenericLambdaSuperArgumentsActivity")]
281277
[InlineData ("MyApp.ComparisonLambdaSuperArgumentsActivity")]
282278
[InlineData ("MyApp.ShiftLambdaSuperArgumentsActivity")]
283279
[InlineData ("MyApp.MethodReferenceSuperArgumentsActivity")]

0 commit comments

Comments
 (0)