Skip to content

Commit 8936f2a

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

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
@@ -3079,17 +3079,8 @@ bool IsActivationFrameworkType (TypeRefData type, string managedTypeName, string
30793079
static bool HasValidSuperArgumentReferences (string superArgumentsString, int parameterCount)
30803080
{
30813081
var tokens = TokenizeJavaExpression (superArgumentsString);
3082-
var lambdaDeclarations = new HashSet<int> ();
3083-
var lambdaScopes = new List<(string Name, int Start, int End)> ();
3084-
for (int i = 0; i < tokens.Count; i++) {
3085-
if (tokens [i].Text != "->") {
3086-
continue;
3087-
}
3088-
int scopeEnd = FindLambdaBodyEnd (tokens, i + 1, superArgumentsString.Length);
3089-
foreach (int declaration in GetLambdaParameterDeclarations (tokens, i)) {
3090-
lambdaDeclarations.Add (declaration);
3091-
lambdaScopes.Add ((tokens [declaration].Text, tokens [i].End, scopeEnd));
3092-
}
3082+
if (tokens.Any (token => token.Text is "->" or "::")) {
3083+
return true;
30933084
}
30943085

30953086
for (int i = 0; i < tokens.Count; i++) {
@@ -3098,10 +3089,7 @@ static bool HasValidSuperArgumentReferences (string superArgumentsString, int pa
30983089
token.Text.Skip (1).Any (c => !char.IsDigit (c))) {
30993090
continue;
31003091
}
3101-
if (lambdaDeclarations.Contains (i) ||
3102-
lambdaScopes.Any (scope => scope.Name == token.Text && token.Start >= scope.Start && token.Start < scope.End) ||
3103-
(i > 0 && tokens [i - 1].Text == ".") ||
3104-
IsMethodReferenceName (tokens, i)) {
3092+
if (i > 0 && tokens [i - 1].Text == ".") {
31053093
continue;
31063094
}
31073095

@@ -3115,7 +3103,7 @@ static bool HasValidSuperArgumentReferences (string superArgumentsString, int pa
31153103
return true;
31163104
}
31173105

3118-
readonly record struct JavaLexicalToken (string Text, int Start, int End, bool IsIdentifier);
3106+
readonly record struct JavaLexicalToken (string Text, bool IsIdentifier);
31193107

31203108
static List<JavaLexicalToken> TokenizeJavaExpression (string value)
31213109
{
@@ -3150,125 +3138,17 @@ static List<JavaLexicalToken> TokenizeJavaExpression (string value)
31503138
while (i < value.Length && IsJavaIdentifierCharacter (value [i])) {
31513139
i++;
31523140
}
3153-
tokens.Add (new JavaLexicalToken (value.Substring (start, i - start), start, i, IsIdentifier: true));
3141+
tokens.Add (new JavaLexicalToken (value.Substring (start, i - start), IsIdentifier: true));
31543142
continue;
31553143
}
31563144
int symbolLength = i + 1 < value.Length &&
31573145
((value [i] == '-' && value [i + 1] == '>') || (value [i] == ':' && value [i + 1] == ':')) ? 2 : 1;
3158-
tokens.Add (new JavaLexicalToken (value.Substring (i, symbolLength), i, i + symbolLength, IsIdentifier: false));
3146+
tokens.Add (new JavaLexicalToken (value.Substring (i, symbolLength), IsIdentifier: false));
31593147
i += symbolLength;
31603148
}
31613149
return tokens;
31623150
}
31633151

3164-
static List<int> GetLambdaParameterDeclarations (IReadOnlyList<JavaLexicalToken> tokens, int arrow)
3165-
{
3166-
if (arrow == 0) {
3167-
return [];
3168-
}
3169-
if (tokens [arrow - 1].IsIdentifier) {
3170-
return [arrow - 1];
3171-
}
3172-
if (tokens [arrow - 1].Text != ")") {
3173-
return [];
3174-
}
3175-
int open = FindMatchingOpenToken (tokens, arrow - 1, "(", ")");
3176-
if (open < 0) {
3177-
return [];
3178-
}
3179-
3180-
var declarations = new List<int> ();
3181-
int segmentStart = open + 1;
3182-
int angleDepth = 0;
3183-
for (int i = segmentStart; i <= arrow - 1; i++) {
3184-
string text = tokens [i].Text;
3185-
if (text == "<") {
3186-
angleDepth++;
3187-
} else if (text == ">" && angleDepth > 0) {
3188-
angleDepth--;
3189-
}
3190-
if ((text == "," && angleDepth == 0) || i == arrow - 1) {
3191-
int segmentEnd = text == "," ? i : arrow - 1;
3192-
for (int j = segmentEnd - 1; j >= segmentStart; j--) {
3193-
if (tokens [j].IsIdentifier) {
3194-
declarations.Add (j);
3195-
break;
3196-
}
3197-
}
3198-
segmentStart = i + 1;
3199-
}
3200-
}
3201-
return declarations;
3202-
}
3203-
3204-
static int FindLambdaBodyEnd (IReadOnlyList<JavaLexicalToken> tokens, int start, int valueLength)
3205-
{
3206-
int parentheses = 0, brackets = 0, braces = 0, genericArguments = 0;
3207-
for (int i = start; i < tokens.Count; i++) {
3208-
string text = tokens [i].Text;
3209-
if (text == "<" && (genericArguments > 0 || IsGenericArgumentOpen (tokens, i))) {
3210-
genericArguments++;
3211-
} else if (text == ">" && genericArguments > 0) {
3212-
genericArguments--;
3213-
}
3214-
if (text == "," && parentheses == 0 && brackets == 0 && braces == 0 && genericArguments == 0) {
3215-
return tokens [i].Start;
3216-
}
3217-
if (genericArguments == 0 &&
3218-
((text == ")" && parentheses == 0) || (text == "]" && brackets == 0) || (text == "}" && braces == 0))) {
3219-
return tokens [i].Start;
3220-
}
3221-
parentheses += text == "(" ? 1 : text == ")" ? -1 : 0;
3222-
brackets += text == "[" ? 1 : text == "]" ? -1 : 0;
3223-
braces += text == "{" ? 1 : text == "}" ? -1 : 0;
3224-
}
3225-
return valueLength;
3226-
}
3227-
3228-
static bool IsGenericArgumentOpen (IReadOnlyList<JavaLexicalToken> tokens, int open)
3229-
{
3230-
int depth = 0;
3231-
for (int i = open; i < tokens.Count; i++) {
3232-
if (tokens [i].Text == "<") {
3233-
depth++;
3234-
} else if (tokens [i].Text == ">" && --depth == 0) {
3235-
if (i + 1 >= tokens.Count) {
3236-
return false;
3237-
}
3238-
string following = tokens [i + 1].Text;
3239-
return following is "(" or "[" or "." or "::" ||
3240-
(tokens [i + 1].IsIdentifier && open > 0 && tokens [open - 1].Text is "." or "::");
3241-
}
3242-
}
3243-
return false;
3244-
}
3245-
3246-
static int FindMatchingOpenToken (IReadOnlyList<JavaLexicalToken> tokens, int close, string openText, string closeText)
3247-
{
3248-
int depth = 0;
3249-
for (int i = close; i >= 0; i--) {
3250-
if (tokens [i].Text == closeText) {
3251-
depth++;
3252-
} else if (tokens [i].Text == openText && --depth == 0) {
3253-
return i;
3254-
}
3255-
}
3256-
return -1;
3257-
}
3258-
3259-
static bool IsMethodReferenceName (IReadOnlyList<JavaLexicalToken> tokens, int identifier)
3260-
{
3261-
int previous = identifier - 1;
3262-
if (previous >= 0 && tokens [previous].Text == "::") {
3263-
return true;
3264-
}
3265-
if (previous < 0 || tokens [previous].Text != ">") {
3266-
return false;
3267-
}
3268-
int open = FindMatchingOpenToken (tokens, previous, "<", ">");
3269-
return open > 0 && tokens [open - 1].Text == "::";
3270-
}
3271-
32723152
static bool IsJavaIdentifierCharacter (char value) =>
32733153
char.IsLetterOrDigit (value) || value == '_' || value == '$';
32743154

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
@@ -876,27 +876,24 @@ public IntBase (int value) {}
876876
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "nested-generic", "success")]
877877
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "nested-generic", "success")]
878878
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "nested-generic", "success")]
879+
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "instanceof-generic", "success")]
880+
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "instanceof-generic", "success")]
881+
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "instanceof-generic", "success")]
879882
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "comparison", "success")]
880883
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "comparison", "success")]
881884
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "comparison", "success")]
882885
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "shift", "success")]
883886
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "shift", "success")]
884887
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "shift", "success")]
885-
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "invalid-bare", "JAVAC0000")]
886-
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "invalid-bare", "XA4262")]
887-
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "invalid-bare", "XA4262")]
888-
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "invalid-parenthesized-bare", "JAVAC0000")]
889-
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "invalid-parenthesized-bare", "XA4262")]
890-
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "invalid-parenthesized-bare", "XA4262")]
891-
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "invalid-generic-reference-bare", "JAVAC0000")]
892-
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "invalid-generic-reference-bare", "XA4262")]
893-
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "invalid-generic-reference-bare", "XA4262")]
894-
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "invalid-generic-construction-bare", "JAVAC0000")]
895-
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "invalid-generic-construction-bare", "XA4262")]
896-
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "invalid-generic-construction-bare", "XA4262")]
897-
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "invalid-comparison-bare", "JAVAC0000")]
898-
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "invalid-comparison-bare", "XA4262")]
899-
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "invalid-comparison-bare", "XA4262")]
888+
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "ordinary-bare", "JAVAC0000")]
889+
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "ordinary-bare", "XA4262")]
890+
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "ordinary-bare", "XA4262")]
891+
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "ordinary-call", "JAVAC0000")]
892+
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "ordinary-call", "XA4262")]
893+
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "ordinary-call", "XA4262")]
894+
[TestCase ("llvm-ir", AndroidRuntime.CoreCLR, "ordinary-arithmetic", "JAVAC0000")]
895+
[TestCase ("trimmable", AndroidRuntime.CoreCLR, "ordinary-arithmetic", "XA4262")]
896+
[TestCase ("trimmable", AndroidRuntime.NativeAOT, "ordinary-arithmetic", "XA4262")]
900897
public void Build_SuperArgumentsLambdaAndMethodReference_MatchJavac (
901898
string typeMapImplementation,
902899
AndroidRuntime runtime,
@@ -917,19 +914,19 @@ public void Build_SuperArgumentsLambdaAndMethodReference_MatchJavac (
917914
"generic-method-reference" => "Helper::<String>p1",
918915
"generic-construction" => "(p1) -> new SimpleEntry<String, String>(p1, p1)",
919916
"nested-generic" => "(p1) -> new SimpleEntry<String, java.util.List<String>>(p1, java.util.Arrays.asList(\\\"a,b\\\", p1))",
917+
"instanceof-generic" => "(p1) -> p1 instanceof java.util.Map<?, ?> ? p1 : p1",
920918
"comparison" => "(int p1) -> p1 < 2 ? p1 : 2",
921919
"shift" => "(int p1) -> p1 >> 1",
922-
"invalid-bare" => "p1 -> p1, p1",
923-
"invalid-parenthesized-bare" => "(p1) -> p1, p1",
924-
"invalid-generic-reference-bare" => "Helper::<String>p1, p1",
925-
"invalid-generic-construction-bare" => "(p1) -> new SimpleEntry<String, String>(p1, p1), p1",
926-
"invalid-comparison-bare" => "(int p1) -> p1 < 2 ? p1 : 2, p1",
920+
"ordinary-bare" => "p1",
921+
"ordinary-call" => "p1.hashCode()",
922+
"ordinary-arithmetic" => "p1 + 1",
927923
_ => throw new InvalidOperationException ($"Unknown super argument shape '{shape}'."),
928924
};
929925
var functionalType = shape switch {
930926
"typed-lambda" => "java.util.function.BiFunction<String, String, String>",
931-
"comparison" or "shift" or "invalid-comparison-bare" => "java.util.function.IntUnaryOperator",
932-
"method-reference" or "generic-method-reference" or "invalid-generic-reference-bare" => "java.util.function.Supplier<String>",
927+
"comparison" or "shift" => "java.util.function.IntUnaryOperator",
928+
"instanceof-generic" => "java.util.function.Function<Object, ?>",
929+
"method-reference" or "generic-method-reference" => "java.util.function.Supplier<String>",
933930
_ => "java.util.function.Function<String, ?>",
934931
};
935932
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)