Skip to content

Commit 765d233

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

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
@@ -3035,17 +3035,8 @@ bool IsActivationFrameworkType (TypeRefData type, string managedTypeName, string
30353035
static bool HasValidSuperArgumentReferences (string superArgumentsString, int parameterCount)
30363036
{
30373037
var tokens = TokenizeJavaExpression (superArgumentsString);
3038-
var lambdaDeclarations = new HashSet<int> ();
3039-
var lambdaScopes = new List<(string Name, int Start, int End)> ();
3040-
for (int i = 0; i < tokens.Count; i++) {
3041-
if (tokens [i].Text != "->") {
3042-
continue;
3043-
}
3044-
int scopeEnd = FindLambdaBodyEnd (tokens, i + 1, superArgumentsString.Length);
3045-
foreach (int declaration in GetLambdaParameterDeclarations (tokens, i)) {
3046-
lambdaDeclarations.Add (declaration);
3047-
lambdaScopes.Add ((tokens [declaration].Text, tokens [i].End, scopeEnd));
3048-
}
3038+
if (tokens.Any (token => token.Text is "->" or "::")) {
3039+
return true;
30493040
}
30503041

30513042
for (int i = 0; i < tokens.Count; i++) {
@@ -3054,10 +3045,7 @@ static bool HasValidSuperArgumentReferences (string superArgumentsString, int pa
30543045
token.Text.Skip (1).Any (c => !char.IsDigit (c))) {
30553046
continue;
30563047
}
3057-
if (lambdaDeclarations.Contains (i) ||
3058-
lambdaScopes.Any (scope => scope.Name == token.Text && token.Start >= scope.Start && token.Start < scope.End) ||
3059-
(i > 0 && tokens [i - 1].Text == ".") ||
3060-
IsMethodReferenceName (tokens, i)) {
3048+
if (i > 0 && tokens [i - 1].Text == ".") {
30613049
continue;
30623050
}
30633051

@@ -3071,7 +3059,7 @@ static bool HasValidSuperArgumentReferences (string superArgumentsString, int pa
30713059
return true;
30723060
}
30733061

3074-
readonly record struct JavaLexicalToken (string Text, int Start, int End, bool IsIdentifier);
3062+
readonly record struct JavaLexicalToken (string Text, bool IsIdentifier);
30753063

30763064
static List<JavaLexicalToken> TokenizeJavaExpression (string value)
30773065
{
@@ -3106,125 +3094,17 @@ static List<JavaLexicalToken> TokenizeJavaExpression (string value)
31063094
while (i < value.Length && IsJavaIdentifierCharacter (value [i])) {
31073095
i++;
31083096
}
3109-
tokens.Add (new JavaLexicalToken (value.Substring (start, i - start), start, i, IsIdentifier: true));
3097+
tokens.Add (new JavaLexicalToken (value.Substring (start, i - start), IsIdentifier: true));
31103098
continue;
31113099
}
31123100
int symbolLength = i + 1 < value.Length &&
31133101
((value [i] == '-' && value [i + 1] == '>') || (value [i] == ':' && value [i + 1] == ':')) ? 2 : 1;
3114-
tokens.Add (new JavaLexicalToken (value.Substring (i, symbolLength), i, i + symbolLength, IsIdentifier: false));
3102+
tokens.Add (new JavaLexicalToken (value.Substring (i, symbolLength), IsIdentifier: false));
31153103
i += symbolLength;
31163104
}
31173105
return tokens;
31183106
}
31193107

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

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)