question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Bug] CodeBehind source generator breaks when use the `x:TypeArguments`

See original GitHub issue

Description

IF you have a View that uses the x:TypeArguments the Source Generator will generate the generic type wrong.

<xct:Popup xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
           xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
           xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
           xmlns:local="clr-namespace:Xamarin.CommunityToolkit.Sample.Pages.Views.Popups"
           Size="{x:Static local:PopupSize.Medium}"
           x:Class="Xamarin.CommunityToolkit.Sample.Pages.Views.Popups.ReturnResultPopup"
           x:TypeArguments="x:String">
//Generated code
[global::Microsoft.Maui.Controls.Xaml.XamlFilePath("C:\\Users\\Jesus\\source\\repos\\MauiBugRepro\\MauiBugRepro\\ReturnResultPopup.xaml")]
	public partial class ReturnResultPopup : global::Xamarin.CommunityToolkit.UI.Views.Popup`1<global::System.String>

I believe that `1 shouldn’t be there.

Steps to Reproduce

  1. Create new maui app add the XCT.MauiCompat nuget
  2. Create a Popup View that declares x:TypeArguments
  3. Try to build

Expected Behavior

Right C# code generated.

Actual Behavior

Wrong C# code generated.

Basic Information

  • Version with issue: 6.0.100-preview.7.1345
  • Last known good version: N/A
  • IDE: VS 2022 Windows
  • Platform Target Frameworks:
    • iOS:
    • Android:
    • UWP:
  • Android Support Library Version:
  • Nuget Packages: N/A
  • Affected Devices: All

Screenshots

Reproduction Link

https://github.com/pictos/MauiBugRepro/tree/GenericPageError

I added the nuget package here this way will be easier to test it.

Workaround

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:3
  • Comments:13 (10 by maintainers)

github_iconTop GitHub Comments

1reaction
StephaneDelcroixcommented, May 4, 2022

Your unit tests ran against Page

the CodeGen is agnostic the to the types it runs on

0reactions
jonpryorcommented, Aug 1, 2023

My guess that the issue is due to cross-assembly type references is wrong. (Reasonable, but wrong.) Assembly references are required, but not themselves the root cause.

The actual problem is around XmlnsDefinitionAttribute support: the “problematic” XAML uses:

<xct:Popup xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
           xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
           xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
           xmlns:local="clr-namespace:MauiApp2304"
           Size="{x:Static local:PopupSize.Medium}"
           x:Class="MauiApp2304.ReturnResultPopup"
           x:TypeArguments="x:String">

In particular, note the xmlns:xct="http://xamarin.com/schemas/2020/toolkit". If I change this to be using:namespace a’la Gh6176.xaml:

<xct:Popup xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
           xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
           xmlns:xct="using:Xamarin.CommunityToolkit.UI.Views"
           xmlns:local="clr-namespace:MauiApp2304"
           Size="{x:Static local:PopupSize.Medium}"
           x:Class="MauiApp2304.ReturnResultPopup"
           x:TypeArguments="x:String">

then the resulting codebehind is valid C#:

public partial class ReturnResultPopup : global::Xamarin.CommunityToolkit.UI.Views.Popup<global::System.String>

After an inordinate amount of hackery to get a new Microsoft.Maui.Controls.SourceGen.dll used by the app build with the following patch applied to dotnet/maui:

diff --git a/src/Controls/src/SourceGen/CodeBehindGenerator.cs b/src/Controls/src/SourceGen/CodeBehindGenerator.cs
index 839f620521..789c87a15f 100644
--- a/src/Controls/src/SourceGen/CodeBehindGenerator.cs
+++ b/src/Controls/src/SourceGen/CodeBehindGenerator.cs
@@ -306,8 +306,8 @@ namespace Microsoft.Maui.Controls.SourceGen
 
 			namedFields = GetNamedFields(root, nsmgr, compilation, caches, cancellationToken);
 			var typeArguments = GetAttributeValue(root, "TypeArguments", XamlParser.X2006Uri, XamlParser.X2009Uri);
-			baseType = GetTypeName(new XmlType(root.NamespaceURI, root.LocalName, typeArguments != null ? TypeArgumentsParser.ParseExpression(typeArguments, nsmgr, null) : null), compilation, caches);
+			baseType = "/* jonp: TryParseXaml */ " + GetTypeName(new XmlType(root.NamespaceURI, root.LocalName, typeArguments != null ? TypeArgumentsParser.ParseExpression(typeArguments, nsmgr, null) : null), compilation, caches);
+			Console.Error.WriteLine ($"# jonp: TryParseXaml: baseType={baseType}");
 
 			// x:ClassModifier attribute
 			var classModifier = GetAttributeValue(root, "ClassModifier", XamlParser.X2006Uri, XamlParser.X2009Uri);
@@ -365,8 +365,8 @@ namespace Microsoft.Maui.Controls.SourceGen
 			string returnType;
 			var ns = GetClrNamespace(xmlType.NamespaceUri);
 			if (ns != null) {
-				returnType = $"{ns}.{xmlType.Name}";
+				Console.Error.WriteLine($"# jonp: GetTypeName: xmlType.Name=`{xmlType.Name}`");
+				returnType = $"/* jonp: GetTypeName */ {ns}.{xmlType.Name}";
 			}
 			else
 			{
@@ -416,9 +416,9 @@ namespace Microsoft.Maui.Controls.SourceGen
 
 					return null;
 				});
+			Console.Error.WriteLine ($"# jonp: GetTypeNameFromCustomNamespace: typeName={typeName}");
 
-			return typeName;
+			return "/* jonp: GetTypeNameFromCustomNamespace */ " + typeName;
 #nullable enable
 		}
 

my resulting source generator output contains:

public partial class ReturnResultPopup : /* jonp: TryParseXaml */ global::/* jonp: GetTypeNameFromCustomNamespace */ Xamarin.CommunityToolkit.UI.Views.Popup`1<global::/* jonp: GetTypeName */ System.String>

suggesting that the “problem” is in: https://github.com/dotnet/maui/blob/ab09cf98bc17f57725e8d088cbf02c3f0723cea3/src/Controls/src/SourceGen/CodeBehindGenerator.cs#L391-L419

Which could be fixed with:

diff --git a/src/Controls/src/SourceGen/CodeBehindGenerator.cs b/src/Controls/src/SourceGen/CodeBehindGenerator.cs
index 097a2d4b89..c06a7a82ab 100644
--- a/src/Controls/src/SourceGen/CodeBehindGenerator.cs
+++ b/src/Controls/src/SourceGen/CodeBehindGenerator.cs
@@ -407,8 +407,14 @@ namespace Microsoft.Maui.Controls.SourceGen
 						if (type.ContainingAssembly.Identity.Name != typeInfo.assemblyName)
 							continue;
 
-						if (IsPublicOrVisibleInternal(type, caches.InternalsVisible))
-							return fullName;
+						if (!IsPublicOrVisibleInternal(type, caches.InternalsVisible))
+							continue;
+						int i = fullName.IndexOf('`');
+						if (i > 0)
+						{
+							fullName = fullName.Substring(0, i);
+						}
+						return fullName;
 					}
 
 					return null;

The Problem: How do I unit test this puppy? To make it work an [assembly: XmlnsDefinition(URL, NAMESPACE)] needs to be used, which does require an external assembly reference. Is there an easy way to set this up?

Read more comments on GitHub >

github_iconTop Results From Across the Web

roslyn - C# Incremental Source Generator caching bug?
I'm trying to wrap my head around the new Roslyn Incremental Source Generators, by making a simple generator, that lists all invoked methods ......
Read more >
Debugging C# Source Generators with Visual Studio 2019 ...
In this post, I provide a step by step guide to debugging C#9 source generators using the new features in Visual Studio 2019...
Read more >
Source Generators
Source Generators is a C# compiler feature that lets C# developers inspect user code as it is being compiled. Source generators create new ......
Read more >
Introducing C# Source Generators - .NET Blog
With a Source Generator, routing can be strongly typed with the necessary strings being generated as a compile-time detail.
Read more >
Incremental Roslyn Source Generators in .NET 6
The performance of the Incremental Source Generators can be improved by optimizing the code for built-in memoization, i.e. caching.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found