dotnet / android

.NET for Android provides open-source bindings of the Android SDK for use with .NET managed languages such as C#
MIT License
1.93k stars 532 forks source link

Add Code DiagnosticAnalyzer and CodeFixProvider for Custom Application classes #9447

Closed dellis1972 closed 2 weeks ago

dellis1972 commented 1 month ago

Context https://github.com/dotnet/android/issues/8410

Building out our DiagnosticAnalyzer support lets add a check to detect if a user has a Custom Application class implemented correctly. When subclassing Android.App.Application, the "Activation Constructor" (IntPtr handle, JniHandleOwnership transfer) must also be provided. Failure to do so results in the following crash

[ERROR] FATAL UNHANDLED EXCEPTION: System.NotSupportedException: Unable to activate instance of type MyApp from native handle 0x7ff1f3b468 (key_handle 0x466b26f).

So lets write a DiagnosticAnalyzer which will check for a constructor which has a specific set of arguments. In this case an IntPtr and JniHandleOwnership. We only do this for classes which derive from Android.App.Application. If we find a class which does not have the constructor we will report a XAA001 issue.

The code fix is designed to inject the required constructor into the syntax tree.

dellis1972 commented 3 weeks ago

@pjcollins is there anything else I need to do for localization? I just added a base Resources.resx file and designer. But that is all. I can't remember if I need to do anything else?

pjcollins commented 3 weeks ago

@pjcollins is there anything else I need to do for localization? I just added a base Resources.resx file and designer. But that is all. I can't remember if I need to do anything else?

A Resources.resx update should be all that is needed initially. This should trigger an initial PR from the OneLoc build system to bring in English strings which are then sent for translation.

jonpryor commented 2 weeks ago

Draft commit message:

[Microsoft.Android.Sdk.Analysis] Warn on missing activation ctors (#9447)

Fixes: https://github.com/dotnet/android/issues/8410

Context: b3079db44e4f1f626d5708e47f0b83153b8548e6
Context: https://learn.microsoft.com/dotnet/csharp/roslyn-sdk/tutorials/how-to-write-csharp-analyzer-code-fix

Commit b3079db4 added a `Microsoft.Android.Sdk.Analysis.dll` assembly
which contained a [`DiagnosticAnalyzer`][0] to suppress IDE0002
warnings.

Extend that support to add a `CustomApplicationAnalyzer` which checks
for the [`(IntPtr, JniHandleOwnership)`][1] constructor on
[`Android.App.Application`][2] subclasses, as this constructor is
currently required.

If the constructor is missing:

    [Application]
    public class MyApp : Application {
    }

then the app will crash during startup:

    System.NotSupportedException: Unable to activate instance of type MyApp from native handle 0x7ff1f3b468 (key_handle 0x466b26f).

If we find an `Application` subclass that is missing the required
constructor, we'll emit a DNAA0001 warning:

    warning DNAA0001: Application class 'MyApp' does not have an Activation Constructor.

Additionally, provide a `CustomApplicationCodeFixProvider` which will
inject the required constructor into the syntax tree.

Finally, rename the previous `XAD0001` warning to `DNAS0001`.
Our convention is as follows:

  * `DNA`: prefix for .NET for Android messages
  * `A` for *Analyzers*, `S` for *Suppressors*
  * 4 digit code.

[0]: https://learn.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.diagnostics.diagnosticanalyzer?view=roslyn-dotnet-4.9.0
[1]: https://learn.microsoft.com/en-us/dotnet/api/android.app.application.-ctor?view=net-android-34.0#android-app-application-ctor(system-intptr-android-runtime-jnihandleownership)
[2]: https://learn.microsoft.com/en-us/dotnet/api/android.app.application?view=net-android-34.0