Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NET Attribute Conversion][generator] Generate NET style attributes #14779

Merged

Conversation

chamons
Copy link
Contributor

@chamons chamons commented Apr 19, 2022

🤞 the final large piece of the saga that is #10170

We won't know until landing this and testing the result but it's the last known hole.....

Summary

This PR teaches our code generator to generate .NET 6 style availability attributes, adds a 4th Cecil test to verify our generated attributes, and a metric ton of API changes to satisfy that test.

Details

The generator work is the core of this PR, and includes:

  • Hacking out chunks of generator.cs that "helpfully" remove duplicate attributes, which are no longer duplicate in the new order that NET6 attributes force upon us. See changes in FilterMinimumVersion and PrintPlatformAttributes
  • Prevent a crash when the generator processes availability attributes with no version included (example: introduced on iOS but no version). See Is64BitiOSOnly.
  • The meat, GetPlatformAttributesToPrint, which synthesizes many attributes "out of thing air" from:
    • The parent context
    • Implied introduced just because the class exists on a given framework at all
    • Implied Catalyst because iOS exists
  • A few cludgy hacks PrintPlatformAttributesNoDuplicates and GenerateProperty because the existing PrintPlatformAttributes did not pass down parent context down, and the refactor was dangerous/too time consuming given time pressure.

There are two intended API changes introduced by the reviews in this PR:

  • GetCurrentInputDevice was obviously intended by availability attributes to exist on Catalyst but due to define confusion was excluded. It is an addition in Microsoft.MacCatalyst.dll only.
  • The NEAppRule constructors were mis-marked on platforms, and were showing up incorrectly on Mac/Catalyst. I corrected the Catalyst one unconditionally, as we have not shipped Catalyst yet, but Mac is only fixed in NET6.

Known API changes

image

image

Limitations

I could spend another week or two polishing this, at minimum. It is being landed in this state due to time pressure.

There are bugs in the generated attributes:

  • Major: Protocols with one set of attributes [TV (9,0)] inlined in types that differ [NoTV] currently unconditionally use the attributes from the protocol, which is wrong. This has always been wrong, but never noticed given how few of them we generated in legacy due to the de-duplication logic and lack of tests. This was deemed too difficult to fix in time since the calls to GetPlatformAttributesToPrint did not pass the "target" type, and I'd have to do wider surgery to wire it through.
  • Major: Obsolete attributes prevent the "implied introduced" attribute from being created, causing some enums to not generate correct attributes.
  • Minor: Protocols that are conditionally included with defines don't have the right attributes. Example: if we include NSItemProviderReading only on iOS those inlined protocols don't have [NoTV] equivalents.
  • Minor: Attributes that are conditionally set as Abstract also don't set the right attributes.

Each of these has cases hit that are Ignored in test code (see IgnoreElementsThatDoNotExistInThatAssembly).

Other things to note (and forgive) include:

  • The gross #if hacks in generator.cs, which are signs that my hacked in code did not gel well with the existing logic. I should in theory extend each check to better handle the NET6 availability attribute reality and then remove logic from GetPlatformAttributesToPrint.
  • GetPlatformAttributesToPrint is a god-function that does too much. It is well documented and calls into child functions where possible, but I could do better with more time.
  • There are zero tests outside of the integration Cecil tests.

Despite this, given time pressure and test coverage I think it is ready to go in.

I've filed #14802 to track the cleanup work from this PR.

- The integration with the existing generator code is not ideal in this
commit, but given time pressures it will hopefully be improved in the future.
- GetPlatformAttributesToPrint is repeating some of the logic that is #if !NET'ed out
in places such as PrintPlatformAttributes because those checks were not robust enough
for the NET6 attribute logic (we generate many more 'duplicate' attributes now)
…remove now unnecessary ignores on other tests
- This is an actual API inclusion, not just attribute change.
- All of the other defines, and attributes imply that GetCurrentInputDevice()
was expected to be on catalyst, but the define on 433 did not include it
@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

Copy link
Member

@rolfbjarne rolfbjarne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good, just a few minor issues.

@@ -189,12 +189,20 @@ public enum AudioObjectPropertySelector : uint
TranslateUIDToBox = 1969841250, // 'uidb'
ClockDeviceList = 1668049699, //'clk#'
TranslateUidToClockDevice = 1969841251, // 'uidc',
#if XAMCORE_3_0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The defines in this enum are somewhat confusing.

I think this would simplify it:

[NoTV][NoWatch]
#if NET
[NoiOS]
#endif
public enum AudioObjectPropertySelector : uint
{
...
#if !NET
 		[Deprecated (PlatformName.iOS, 15,0, message : "Use the 'ProcessIsMain' element instead.")]
#endif
 		[Deprecated (PlatformName.MacCatalyst, 15,0, message : "Use the 'ProcessIsMain' element instead.")]
 		[Deprecated (PlatformName.MacOSX, 12,0, message : "Use the 'ProcessIsMain' element instead.")]
 		[Obsolete ("Use the 'ProcessIsMain' element instead.")]
 		ProcessIsMaster = 1835103092, // 'mast'
 		[MacCatalyst (15,0), Mac (12,0)]
 		ProcessIsMain = 1835100526, // 'main'
...
 		[MacCatalyst (15,0), Mac (12,0)]
 		ProcessMute = 1634758765, // 'appm'
}

That said, the changes here look correct, so this could go in another PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like it, let's save it for a follow up PR.

@@ -74,6 +77,7 @@ interface CNContactPickerDelegate
void DidClose (CNContactPicker picker);
}
#else
[NoMac]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason you didn't merge the CNContactPickerDelegate definitions like you did for CNContactViewController?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was just found later and I started running into more time pressure to get this done.

tests/cecil-tests/AttributeTest.cs Outdated Show resolved Hide resolved
#if DEBUG
Console.WriteLine(assemblyPath);
#endif
if (!assemblyPath.Contains("Xamarin.Mac.dll")) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no "Xamarin.Mac.dll" anymore for .NET (it's "Microsoft.macOS.dll"), so this seems wrong.

Copy link
Contributor Author

@chamons chamons Apr 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a cludge to only run one test more quickly (from back before the rename). 🤦

Let me remove and re-run.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, this uncovered a few test failures.... looking into those now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed!

src/generator.cs Outdated Show resolved Hide resolved
src/generator.cs Outdated Show resolved Hide resolved
src/generator.cs Outdated Show resolved Hide resolved
chamons and others added 2 commits April 20, 2022 09:27
Co-authored-by: Rolf Bjarne Kvinge <rolf@xamarin.com>
Co-authored-by: Rolf Bjarne Kvinge <rolf@xamarin.com>
@chamons chamons added the do-not-merge Do not merge this pull request label Apr 20, 2022
@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@chamons chamons removed the do-not-merge Do not merge this pull request label Apr 20, 2022
@chamons chamons requested a review from rolfbjarne April 20, 2022 17:18
@chamons
Copy link
Contributor Author

chamons commented Apr 20, 2022

@rolfbjarne - Requesting re-review just because the last commit was large (fixing the issue you found).

@chamons chamons added the not-notes-worthy Ignore for release notes label Apr 20, 2022
Copy link
Contributor

@tj-devel709 tj-devel709 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small typo I believe in a method name, but the other new things look good to me!

@vs-mobiletools-engineering-service2

This comment has been minimized.

@@ -931,19 +925,61 @@ public override string ToString ()
builder.AppendLine ("#if __MACOS__");
break;
case PlatformName.MacCatalyst:
builder.AppendLine ("#if __MACCATALYST__");
builder.AppendLine ("#if __MACCATALYST__ && !__IOS__ && !__MACOS__");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The && !__MACOS__ part shouldn't be needed, but it doesn't hurt either.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed!

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@chamons
Copy link
Contributor Author

chamons commented Apr 29, 2022

Generator test failure looks legit somehow, fixing (Introspection passes locally for me).

@chamons
Copy link
Contributor Author

chamons commented Apr 29, 2022

Looks like the generator test actually caught a logic bug in the generator change. In NET6 I assume that all namespaces must be one of the Apple binding one, else we must be unsupported and thus skip attributes.

This completely ignored 3rd party bindings.

@@ -832,7 +832,7 @@ public enum MTLFeatureSet : ulong {
[iOS (9,0)][Mac (10,11)]
[Native]
public enum MTLLanguageVersion : ulong {
[NoMac]
[NoMac][NoMacCatalyst]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we care about consistence between [NoMac][NoMacCatalyst] and the previous usage of [...NoMac, NoMacCatalyst]?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. We are absurdly inconsistent.

@@ -931,19 +925,61 @@ public override string ToString ()
builder.AppendLine ("#if __MACOS__");
break;
case PlatformName.MacCatalyst:
builder.AppendLine ("#if __MACCATALYST__");
builder.AppendLine ("#if __MACCATALYST__ && !__IOS__");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know the overall usage - is it guaranteed that the StringBuilder is at end-of-line at this point?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty much, though invariants are tough to pin down in the generator since it's older code with few tests.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK - for the future:

static class StringBuilderExtensions {
    public static StringBuilder AppendLineIfNeeded (this StringBuilder sb)
    {
        if (sb.Length == 0) return sb;
        return sb [sb.Length - 1] == '\n' ? sb : sb.Append ('\n');
    }
    public static StringBuilder AppendLineIfNeeded (this StringBuilder sb, string text)
        => return sb.AppendLineIfNeeded().Append(text);
}

}
}

HashSet<string> GetFrameworkListForPlatform (PlatformName platform)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the future, this type of code can be simplified with a switch expression:

var frameworkList = platform switch {
    PlatformName.iOS => Frameworks.iosframeworks,
    PlatformName.TvOS => Frameworks.tvosframeworks,
    PlatformName.MacOSX => Frameworks.macosframeworks,
    PlatformName.MacCatalyst => Frameworks.maccatalstframeworks,
    _ => new HashSet<string>(),
};
return new HashSet<string>(frameworkList.Select(x => x.ToLower (CultureInfo.InvariantCulture)));

default:
throw new NotImplementedException ($"FindNamespace on {item} of type {item.GetType()}");
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here:

static string FindNamespace (MemberInfo item) => item switch {
    TypeInfo type => type.Namespace,
    PropertyInfo prop => prop.DeclaringType.Namespace,
    MethodInfo meth => meth.DeclaringType.Namespace,
   _ => throw new NotImplementedException ("..."),
}

Also - should this have a case for events?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Events are never (?) in bindings, I'd rather crash and find out than add it and hope it works.

…mespaceNotIncluded always assuming we're core
@@ -7596,17 +7596,17 @@ interface AVFragmentedMovie_AVFragmentedMovieTrackInspection
AVFragmentedMovieTrack[] GetTracks (AVMediaCharacteristics mediaCharacteristic);

[Async]
[Watch (8,0), TV (15,0), Mac (12,0), iOS (15,0), MacCatalyst (15,0)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean is present in the default min version? What am I missing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type itself is marked with NoTV, and my tests screamed about the inconsistency.

@chamons
Copy link
Contributor Author

chamons commented Apr 29, 2022

Generator test should be fixed.

Copy link
Member

@mandel-macaque mandel-macaque left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to re-think the 10000 ones switches in the future, is getting out of hand.

static bool IgnoreElementsThatDoNotExistInThatAssembly (string member)
{
// Xkit has many platform specific bits in AppKit/UIKit and is a mess to get right
if (member.StartsWith ("Kit")) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All this can be a lot nicer with a switch and since we have the new c# we could put all in the same switch.

@chamons
Copy link
Contributor Author

chamons commented Apr 29, 2022

@mandel-macaque - I fully the switches in AttributesTest.cs are absurd, but they should be temporary until #14802 is fixed.

Copy link
Member

@dalexsoto dalexsoto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

@vs-mobiletools-engineering-service2
Copy link
Collaborator

📋 [PR Build] API Diff 📋

API Current PR diff

ℹ️ API Diff (from PR only) (please review changes)

View API diff
View dotnet API diff
View dotnet legacy API diff
View dotnet iOS-MacCatalayst API diff

API diff

✅ API Diff from stable

View API diff
View dotnet API diff
View dotnet legacy API diff
View dotnet iOS-MacCatalayst API diff

Generator diff

ℹ️ Generator Diff (please review changes)

Pipeline on Agent XAMBOT-1109.Monterey'
Hash: 388d6faf3c0b977231e19ff318b77726d6d3eec9

@vs-mobiletools-engineering-service2
Copy link
Collaborator

📚 [PR Build] Artifacts 📚

Packages generated

View packages

Pipeline on Agent XAMBOT-1101.Monterey'
Hash: 388d6faf3c0b977231e19ff318b77726d6d3eec9

@vs-mobiletools-engineering-service2
Copy link
Collaborator

❌ [PR Build] Tests on macOS Mac Catalina (10.15) failed ❌

Failed tests are:

  • introspection

Pipeline on Agent
Hash: 388d6faf3c0b977231e19ff318b77726d6d3eec9

@vs-mobiletools-engineering-service2
Copy link
Collaborator

❌ [PR Build] Tests on macOS M1 - Mac Big Sur (11.5) failed ❌

Failed tests are:

  • introspection
  • linksdk

Pipeline on Agent
Hash: 388d6faf3c0b977231e19ff318b77726d6d3eec9

@vs-mobiletools-engineering-service2
Copy link
Collaborator

✅ [CI Build] Tests passed on VSTS: simulator tests iOS. ✅

Tests passed on VSTS: simulator tests iOS.

🎉 All 150 tests passed 🎉

Pipeline on Agent XAMBOT-1108.Monterey'
Merge 388d6fa into 75f5976

@chamons chamons merged commit 1dcefc9 into xamarin:main May 2, 2022
@chamons chamons deleted the reconvert_attributes_with_generator_fixes_smash branch May 2, 2022 14:45
@dalexsoto
Copy link
Member

/sudo backport release/6.0.3xx

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Backport Job to branch release/6.0.3xx Created! The magic is happening here

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Hooray! Backport succeeded! Please see https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=6103169 for more details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
do-not-merge Do not merge this pull request not-notes-worthy Ignore for release notes run-dotnet-tests Run all the .NET tests
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants