Skip to content

[Xamarin.Android.Build.Tasks] Add more warning codes #2258

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

Merged
merged 1 commit into from
Oct 5, 2018

Conversation

brendanzagaeski
Copy link
Contributor

Context: #1560

  • I investigated the code paths that led into the LogWarning() in
    GenerateResourceDesigner.AddRename(). I could not find any way to
    hit that message with the current code. Moreover, the only reports of
    the message I could find on the web were from capitalization
    mismatches, and those are now explicitly ignored by the use of the
    StringComparison.OrdinalIgnoreCase argument in the call to
    string.Compare(). Since this message does not currently indicate an
    actionable problem, I changed it from a warning to a debug message.

  • Neither of the warnings in
    GetAdditionalResourcesFromAssemblies.AddAttributeValue() is
    actionable for Xamarin.Android app developers. The first warning can
    only arise if a new attribute name has been added to the switch
    statement in DoExecute(). The second warning can only occur in a
    library that uses one of those attributes. Since the attributes are
    not formally documented, they are currently only intended for use by
    the Xamarin team. Since these warnings aren't aimed at end-users,
    they don't need to have their own codes. So for now, I just updated
    the warnings to reuse the errorCode.

  • The first warning in
    GetAdditionalResourcesFromAssemblies.MakeSureLibraryIsInPlace() is
    just an informational message. The download step is expected to be
    skipped during design-time builds. I changed the warning to a debug
    message accordingly.

  • I changed the warning in ReadAdditionalResourcesFromAssemblyCache to
    a debug message because it is just informational. For example, in the
    normal process of building application projects, the
    Xamarin.Android.Common.targets checks if CacheFile exists before it
    invokes the task, so an absent CacheFile is often normal. In cases
    where the warning could be actionable for an end-user, the warning
    would indicate that something went wrong earlier when creating the
    CacheFile in GetAdditionalResourcesFromAssemblies, so even in that
    case this warning would not be needed because more actionable messages
    should come from the earlier task. On top of that, this whole old
    mechanism of downloading external files is rarely used now that the
    large majority of the NuGet packages from the Xamarin team have been
    updated to use the newer Xamarin.Build.Download mechanism.

  • I also changed the warnings in ReadImportedLibrariesCache and
    ReadLibraryProjectImportsCache to debug messages for similar reasons.
    A missing cache file in one of these tasks indicates that something
    went wrong during the corresponding earlier GetImportedLibraries or
    ResolveLibraryProjectImports task, so any actionable messages would
    need to get logged in the earlier task instead.

  • The warnings in
    ResolveAssemblies.ResolveRuntimeAssemblyForReferenceAssembly()
    should not occur during normal use. They both depend on generated
    content related to the NuGet target framework moniker. Based on these
    considerations, I assigned just one shared warning code to both
    warnings for now.


### XA2xxx Linker

### XA3xxx AOT

### XA4xxx Code Generation

+ [XA4214](xa4214.md): Duplicate managed type found! Mappings between managed types and Java types must be unique. First Type: '{0}'; Second Type: '{1}'.
+ [XA4215](xa4215.md): Duplicate Java type found! Mappings between managed types and Java types must be unique. First Type: '{0}'; Second Type: '{1}'.
Copy link
Contributor

Choose a reason for hiding this comment

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

@brendanzagaeski does the wording on one of these messages need to be flipped? eg.

Mappings between managed types and Java types must be unique
Mappings between Java types and managed types must be unique

I suspect the two checks are from the opposite point of view. So we should reword the message to reflect which point of view we were using? maybe?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, ensuring clear language in the actual message that comes from the warnings is good to do. For this pass, I was only planning to update messages "opportunistically" if I saw cases where an idea came to mind immediately as I was reading them for a better wording. But I'd be happy to spend a little more time reviewing the wording as I go, if that'd be useful. For these 2 particular warnings, I also had a hunch that users might not run into them often (we'll know better once we start getting the telemetry from the warning codes). So I didn't spend too much time thinking about the wording yet.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I took another look at this warning & error pair today. It occurred to me that it might be best to rephrase these messages to be more like the error that Csc gives for similar type conflicts. That led me to see that the current messages use a slightly different way of splitting up the type and assembly name compared to the Csc message, so getting everything to match up closely would take some extra work. Long story short, I took a try at updating the messages, but I'm not sure if the new wording better overall. If it does look like an improvement, I can add it to this pull request.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think improving the wording is a good idea. I'm unsure whether the current suggestion is a net improvement.

Consider a solution with two library projects, referenced by the app project, which contain the following class:

using System;
using Android.Runtime;

namespace Lib1
{
  [Register ("examplelib.EmptyClass")]
  public class EmptyClass : Java.Lang.Object
  {
  }
}

This elicits the warning (newlines added for readability):

warning : Duplicate managed type found! Mappings between managed types and Java types must be unique.
 First Type: 'Lib1.EmptyClass, Lib1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null';
Second Type: 'Lib1.EmptyClass, Lib2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

Hilariously, if we update the project structure so that Lib1 has Lib1.EmptyClass and Lib2 has Lib2.EmptyClass -- instead of both Lib1 and Lib2 providing Lib1.EmptyClass -- then we get an error (newlines added for readability):

error : Duplicate Java type found! Mappings between managed types and Java types must be unique.
 First Type: 'Lib1.EmptyClass, Lib1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null';
Second Type: 'Lib2.EmptyClass, Lib2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'

I find this hilarious, as it implies one form of ambiguity is worse than another, even though either way we have ambiguity. :-/

That setup aside, if we imagine the suggested XA4214 warning message, we'd have:

The managed type 'Lib1.EmptyClass' exists as both 'Lib1.EmptyClass, Lib1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' and Lib1.EmptyClass, Lib2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. An Android Callable Wrapper will only be generated for 'Lib1.EmptyClass, Lib1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

Is this better? Not immediately, no; it's not actionable. It doesn't inform why this might be a problem -- which arguably could/should instead be in the docs -- nor does it have any suggestion of how to fix it.

(The fact that we have assembly-qualified names in here also makes me think we'd be better off with multi-line messages here!)

Copy link
Contributor

Choose a reason for hiding this comment

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

After pondering the corresponding documentation, how's this for an improved warning message?

The managed type `Lib1.EmptyClass` exists in the assemblies `Lib1`, `Lib2`.  Please refactor the managed type names so that they are not identical.

C#-wise, this would require additional changes to <GenerateJavaStubs/> so that we can properly capture all the assemblies that contain duplicate types, instead of the current code which emits the warning as soon as it finds a duplicate, and then will re-issue the "same" warning every time.

For example, my previous examples have all had two assemblies (Lib1 & Lib2) with a Lib1.EmptyClass type. What happens when there are three assemblies with the same type? Four assemblies? 10? With the current approach, we'll emit assemblies.Length-1 warnings, which is potentially very noise and not as actionable.

@@ -0,0 +1,12 @@
# Compiler Warning XA0118

These warning indicate either that the Xamarin.Android project has a value in
Copy link
Contributor

Choose a reason for hiding this comment

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

Grammar. These warnings :)

the `$(NuGetTargetMoniker)` MSBuild property that NuGet does not recognize or
that the *obj\\project.assets.json* file generated by the NuGet build targets
for the project is missing a `targets` section that matches the
`$(NuGetTargetMoniker)`. These warnings should not arise in normal use.
Copy link
Contributor

Choose a reason for hiding this comment

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

I would break the previous sentence up in to two at the or. Its currently difficult to read.

android:id="@+id/text1" />
```

The "naive type name fixup" tries to ensure that any fully-qualified type name
Copy link
Contributor

Choose a reason for hiding this comment

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

should naive be native ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good sanity-check :-) In this case as I understand it, it is indeed intended to be "naive" because the fixup approach is fairly simplistic. Context:
https://github.com/xamarin/xamarin-android/blob/14d91c314f9c9f2ba7b1d69556b6b2044afb6ab5/src/Xamarin.Android.Build.Tasks/Tasks/CalculateLayoutCodeBehind.cs#L320-L331

@jonpryor
Copy link
Contributor

jonpryor commented Oct 3, 2018

@brendanzagaeski: For future reference, please use separate PRs for each added warning/error code. Smaller & more frequent PRs are preferable to larger and less frequent PRs.

@brendanzagaeski
Copy link
Contributor Author

please use separate PRs for each added warning/error code

👍 Will do.


If the same fully qualified C# type name exists in two or more assemblies and
both C# types inherit from `Java.Lang.Object`, then the build process will only
generate an Android Callable Wrapper for *one* of them.
Copy link
Contributor

Choose a reason for hiding this comment

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

...now that we're digging into this, an obvious question is this: Why does anybody care?

Additionally, the description is wrong.

(Also, let's stop using "Android Callable Wrapper" and stick with "Java Callable Wrapper". ;-)

Consider a variation on the previous repro instructions: two assemblies which both declare the "same" C# type:

namespace Lib1
{
  public class EmptyClass : Java.Lang.Object
  {
  }
}

We thus have two different Lib1.EmptyClass types running around. However, because there is no [Register], then we hit the default "md5-ify everything" approach, which means we can emit two separate Java Callable Wrapper types: md56bf89f81d87b2a3b578f763649ead9ef.EmptyClass for Lib1.EmptyClass, Lib1 and md551eaf02b2ef90dc8aacda5445b93be5c.EmptyClass for Lib1.EmptyClass, Lib2.

We can -- do -- generate Java Callable Wrappers for both types.

Thus, why care that we have two separate "Lib1.EmptyClass" types running around? What's the actual problem?

The actual problem comes in places where an assembly cannot be specified, such as within .axml files. There, if we used <Lib1.EmptyClass/>, there is no way to say "use the EmptyClass type from Lib1" vs. "use the EmptyClass type from Lib2". It's ambiguous.

However, fragments allow avoiding this, e.g. by using <fragment type="Lib1.EmptyClass, Lib1" />. (No idea if anyone actually uses that functionality, but it exists.) Again, though, if you use <fragment type="Lib1.EmptyClass" /> -- no assembly -- then one of the types is picked. The first one.

What is the fix? Change the type names so that they have different C# Namespace.Type names. The documentation should likewise mention how to fix the warning.

# Compiler Error XA4215

This error indicates that two or more C# types are emitting the same fully
qualified Java type name. To resolve this error, change the `[Register]`
Copy link
Contributor

Choose a reason for hiding this comment

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

The solution should be in a new paragraph.

Regarding the suggested new error text, we'd currently emit:

error : Duplicate Java type found! Mappings between managed types and Java types must be unique. First Type: 'Lib1.EmptyClass, Lib1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'; Second Type: 'Lib2.EmptyClass, Lib2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'

In the spirit of this suggestion for XAX4214, what about:

error XA4215: The Java type `examplelib.EmptyClass` is generated by more than one managed type. Please change the [Register] attribute so that the same Java type is not emitted.
error XA4215:   `examplelib.EmptyClass` generated by: Lib1.EmptyClass, Lib1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
error XA4215:   `examplelib.EmptyClass` generated by: Lib1.EmptyClass, Lib2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

If we get really extravagant, we could emit the filename & line number information for the class declarations of the offending types:

path/to/Lib1/ExampleClass.cs:7: error XA4215: The Java type ...
path/to/Lib1/ExampleClass.cs:7: error XA4215:   `examplelib.EmptyClass` generated by: Lib1.EmptyClass, Lib1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
path/to/Lib2/ExampleClass.cs:7: error XA4215:   `examplelib.EmptyClass` generated by: Lib2.EmptyClass, Lib1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

@jonpryor
Copy link
Contributor

jonpryor commented Oct 4, 2018

please use separate PRs for each added warning/error code

👍 Will do.

Continuing the aside, just the back & forth over the past day suggests why "one PR per update" is better here. More than half of this PR is fine/acceptable: XA0118, XA1005, the LogDebugMessage() changes.

XA4214 and XA4215 have completely blown things up. :-)

In the interests of moving forward, could you split up this PR so it only includes the XA0118, XA1005, the LogDebugMessage() changes? We can then deal with XA4214 and XA4215 separately.

Context: dotnet#1560

* I investigated the code paths that led into the `LogWarning()` in
  `GenerateResourceDesigner.AddRename()`.  I could not find any way to
  hit that message with the current code.  Moreover, the only reports of
  the message I could find on the web were from capitalization
  mismatches, and those are now explicitly ignored by the use of the
  `StringComparison.OrdinalIgnoreCase` argument in the call to
  `string.Compare()`.  Since this message does not currently indicate an
  actionable problem, I changed it from a warning to a debug message.

* Neither of the warnings in
  `GetAdditionalResourcesFromAssemblies.AddAttributeValue()` is
  actionable for Xamarin.Android app developers.  The first warning can
  only arise if a new attribute name has been added to the `switch`
  statement in `DoExecute()`.  The second warning can only occur in a
  library that uses one of those attributes.  Since the attributes are
  not formally documented, they are currently only intended for use by
  the Xamarin team.  Since these warnings aren't aimed at end-users,
  they don't need to have their own codes.  So for now, I just updated
  the warnings to reuse the `errorCode`.

* The first warning in
  `GetAdditionalResourcesFromAssemblies.MakeSureLibraryIsInPlace()` is
  just an informational message.  The download step is *expected* to be
  skipped during design-time builds.  I changed the warning to a debug
  message accordingly.

* I changed the warning in `ReadAdditionalResourcesFromAssemblyCache` to
  a debug message because it is just informational.  For example, in the
  normal process of building application projects, the
  Xamarin.Android.Common.targets checks if `CacheFile` exists before it
  invokes the task, so an absent `CacheFile` is often normal.  In cases
  where the warning could be actionable for an end-user, the warning
  would indicate that something went wrong earlier when creating the
  `CacheFile` in `GetAdditionalResourcesFromAssemblies`, so even in that
  case this warning would not be needed because more actionable messages
  should come from the earlier task.  On top of that, this whole old
  mechanism of downloading external files is rarely used now that the
  large majority of the NuGet packages from the Xamarin team have been
  updated to use the newer Xamarin.Build.Download mechanism.

* I also changed the warnings in `ReadImportedLibrariesCache` and
  `ReadLibraryProjectImportsCache` to debug messages for similar
  reasons.  A missing cache file in one of these tasks indicates that
  something went wrong during the corresponding earlier
  `GetImportedLibraries` or `ResolveLibraryProjectImports` task, so any
  actionable messages would need to get logged in the earlier task
  instead.

* The warnings in
  `ResolveAssemblies.ResolveRuntimeAssemblyForReferenceAssembly()`
  should not occur during normal use.  They both depend on *generated*
  content related to the NuGet target framework moniker.  Based on these
  considerations, I assigned just one shared warning code to both
  warnings for now.
@brendanzagaeski
Copy link
Contributor Author

I have now updated this pull request to omit the changes for XA4214 and XA4215 so that we can follow-up on those separately.

@jonpryor jonpryor dismissed dellis1972’s stale review October 5, 2018 19:32

The XA4214/XA4215 errors have been split out.

@jonpryor jonpryor merged commit 2e88ed8 into dotnet:master Oct 5, 2018
jonpryor pushed a commit that referenced this pull request Oct 8, 2018
Context: #1560

Change the `LogWarning()` within `<GenerateResourceDesigner>` to a
`LogDebugMessage()`.  I could not find any way to hit that message
with the current code.  Moreover, the only reports of the message I
could find on the web were from capitalization mismatches, and those
are now explicitly ignored by the use of the
`StringComparison.OrdinalIgnoreCase` argument in the call to
`string.Compare()`.  Since this message does not currently indicate
an actionable problem, I changed it from a warning to a debug message.

Several of the `LogWarning()` calls within
`<GetAdditionalResourcesFromAssemblies/>` are not actionable.  The
"Attribute {0} doesn't have..." message cannot be fixed by
developers -- it can only be fixed by the person who has built the
assembly containing the `Android.IncludeAndroidResourcesFromAttribute`,
`Java.Interop.JavaLibraryReferenceAttribute`, or
`Android.NativeLibraryReferenceAttribute`  assembly-level attributes.
Ditto the "Attribute {0} constructor..." warning: it's not fixable
by those who will see the warnings.
Turn these warnings into `LogDebugMessage()`s.

The "Skipping download of" warning from
`<GetAdditionalResourcesFromAssemblies/>` isn't actionable or
otherwise useful.  Turn it into a `LogDebugMessage()`.

The warning within `<ReadAdditionalResourcesFromAssemblyCache/>`
is likewise informational and not actionable.  Replace it with a
`LogDebugMessage()` call.  Additionally, this whole old mechanism of
downloading external files is rarely used now that the large majority
of the NuGet packages from the Xamarin team have been updated to use
the newer Xamarin.Build.Download mechanism.

The warnings within `<ReadImportedLibrariesCache/>` and
`<ReadLibraryProjectImportsCache/>` are likewise informational and
not actionable.  A missing cache file in one of these tasks indicates
that something went wrong during the corresponding earlier
`<GetImportedLibraries/>` or `<ResolveLibraryProjectImports/>` tasks,
so any actionable messages would need to get logged in the earlier
tasks instead.

Finally, the warnings in
`ResolveAssemblies.ResolveRuntimeAssemblyForReferenceAssembly()`
should not occur during normal use.  They both depend on *generated*
content related to the NuGet target framework moniker.  Based on
these considerations, I assigned just one shared XA0118 warning code
to both warnings for now.
brendanzagaeski added a commit to brendanzagaeski/xamarin-android that referenced this pull request Oct 26, 2018
…vaStubs

Context: dotnet#1560

Background discussion about the new wording for this particular warning
and error:
- dotnet#2258 (comment)
- dotnet#2258 (comment)

The new wording aims to be more actionable.  It is also more compact
than the old wording when there are multiple conflicts.

A possible future enhancement could be to move the warning into the
`ConvertCustomView` task so that it only appears when a managed type
name from an Android resource file matches more than one line in the
acw-map.  That way, if a user wants to solve the issue by using
`[Register]` attributes or assembly-qualified type names rather than
renaming the managed types, the build process will automatically stop
showing the warning.
brendanzagaeski added a commit to brendanzagaeski/xamarin-android that referenced this pull request Oct 29, 2018
…vaStubs

Context: dotnet#1560

Background discussion about the new wording for this particular warning
and error:
- dotnet#2258 (comment)
- dotnet#2258 (comment)

The new wording aims to be more actionable.  It is also more compact
than the old wording when there are multiple conflicts.

A possible future enhancement could be to move the warning into the
`ConvertCustomView` task so that it only appears when a managed type
name from an Android resource file matches more than one line in the
acw-map.  That way, if a user wants to solve the issue by using
`[Register]` attributes or assembly-qualified type names rather than
renaming the managed types, the build process will automatically stop
showing the warning.
brendanzagaeski added a commit to brendanzagaeski/xamarin-android that referenced this pull request Nov 2, 2018
This documentation was meant to be part of:
dotnet#2258

I accidentally removed these pages from that pull request when I was
updating it to exclude the changes for XA4214 and XA4215.
jonpryor pushed a commit that referenced this pull request Nov 5, 2018
This documentation was meant to be part of 2e88ed8.

I accidentally removed these pages from PR #2258 when I was updating
it to exclude the changes for XA4214 and XA4215.
brendanzagaeski added a commit to brendanzagaeski/xamarin-android that referenced this pull request Nov 9, 2018
…vaStubs

Context: dotnet#1560

Background discussion about the new wording for this particular warning
and error:
- dotnet#2258 (comment)
- dotnet#2258 (comment)

The new wording aims to be more actionable.  It is also more compact
than the old wording when there are multiple conflicts.

A possible future enhancement could be to move the warning into the
`ConvertCustomView` task so that it only appears when a managed type
name from an Android resource file matches more than one line in the
acw-map.  That way, if a user wants to solve the issue by using
`[Register]` attributes or assembly-qualified type names rather than
renaming the managed types, the build process will automatically stop
showing the warning.
brendanzagaeski added a commit to brendanzagaeski/xamarin-android that referenced this pull request Nov 27, 2018
…vaStubs

Context: dotnet#1560

Background discussion about the new wording for this particular warning
and error:
- dotnet#2258 (comment)
- dotnet#2258 (comment)

The new wording aims to be more actionable.  It is also more compact
than the old wording when there are multiple conflicts.

A possible future enhancement could be to move the warning into the
`ConvertCustomView` task so that it only appears when a managed type
name from an Android resource file matches more than one line in the
acw-map.  That way, if a user wants to solve the issue by using
`[Register]` attributes or assembly-qualified type names rather than
renaming the managed types, the build process will automatically stop
showing the warning.
brendanzagaeski added a commit to brendanzagaeski/xamarin-android that referenced this pull request Jan 8, 2019
…vaStubs

Context: dotnet#1560

Background discussion about the new wording for this particular warning
and error:

  * dotnet#2258 (comment)
  * dotnet#2258 (comment)

The new wording aims to be more actionable.  It is also more compact
than the old wording when there are multiple conflicts.

The `Dictionary` initializations follow the style used in [c362fe5][0].
Since these 2 new dictionaries should usually be empty, they are set to
an initial capacity of 0.  The current implementation of `Dictionary`
defaults to an initial capacity of 0, but the [documentation][1] doesn't
mention 0 specifically, so it seems reasonable to specify it.  Another
idea would be to initialize each dictionary only when a corresponding
conflict is found, but that might make the code trickier to read.

A possible future enhancement could be to move the warning into the
`ConvertCustomView` task so that it only appears when a managed type
name from an Android resource file matches more than one line in the
acw-map.  That way, if a user wants to solve the issue by using
`[Register]` attributes or assembly-qualified type names rather than
renaming the managed types, the build process will automatically stop
showing the warning.

[0]: dotnet@c362fe5
[1]: https://docs.microsoft.com/dotnet/api/system.collections.generic.dictionary-2.-ctor
@github-actions github-actions bot locked and limited conversation to collaborators Feb 2, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants