Skip to content

Commit

Permalink
Merge pull request #4543 from unoplatform/dev/jela/xaml-tuples
Browse files Browse the repository at this point in the history
fix(generation): Fixes invalid Tuples expansion using Roslyn 3.5 and later
  • Loading branch information
mergify[bot] committed Nov 17, 2020
2 parents 786a182 + e928bde commit c7bebb2
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using Microsoft.Build.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Uno.UI.SourceGenerators.XamlGenerator.Utils;

namespace Uno.UI.SourceGenerators.Tests
{
[TestClass]
public class Given_SymbolExtension
{
[TestMethod]
[DataRow("int", "int")]
[DataRow("double", "double")]
[DataRow("System.Collections.Generic.IList<int>", "global::System.Collections.Generic.IList<int>")]
[DataRow("System.Collections.Generic.IList<System.Disposable>", "global::System.Collections.Generic.IList<global::System.Disposable>")]
[DataRow("System.Collections.Generic.IDictionary<int, System.Disposable>", "global::System.Collections.Generic.IDictionary<int, global::System.Disposable>")]
[DataRow("(int, int)", "(int, int)")]
[DataRow("(int, System.Disposable)", "(int, global::System.Disposable)")]
[DataRow("System.Collections.Generic.IList<(int, System.Disposable)>", "global::System.Collections.Generic.IList<(int, global::System.Disposable)>")]
[DataRow("System.Collections.Generic.IList<(string, string, double)>", "global::System.Collections.Generic.IList<(string, string, double)>")]
public void When_GetFullyQualifiedString(string input, string expected)
{
var compilation = CreateTestCompilation(input);

if (compilation.GetTypeByMetadataName("Test") is INamedTypeSymbol testSymbol)
{
if (testSymbol.GetAllMembersWithName("_myField").FirstOrDefault() is IPropertySymbol myField)
{
var actual = myField.Type.GetFullyQualifiedType();
Assert.AreEqual<string>(expected, actual);
}
else
{
Assert.Fail();
}
}
else
{
Assert.Fail();
}
}

private static Compilation CreateTestCompilation(string type)
{
var programPath = @"Program.cs";
var programText = $"public class Test {{ public static {type} _myField {{ get; set; }} }}";
var programTree = CSharpSyntaxTree
.ParseText(programText)
.WithFilePath(programPath);

SyntaxTree[] sourceTrees = { programTree };

MetadataReference mscorlib = MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location);
MetadataReference codeAnalysis = MetadataReference.CreateFromFile(typeof(SyntaxTree).GetTypeInfo().Assembly.Location);
MetadataReference csharpCodeAnalysis = MetadataReference.CreateFromFile(typeof(CSharpSyntaxTree).GetTypeInfo().Assembly.Location);
MetadataReference[] references = { mscorlib, codeAnalysis, csharpCodeAnalysis };

return CSharpCompilation.Create("ConsoleApplication",
sourceTrees,
references,
new CSharpCompilationOptions(OutputKind.ConsoleApplication));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
<PackageReference Include="MSTest.TestAdapter" Version="2.1.2" />
<PackageReference Include="MSTest.TestFramework" Version="2.1.1" />
<PackageReference Include="coverlet.collector" Version="1.3.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.3.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.6" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Uno.UI.SourceGenerators\Uno.UI.SourceGenerators.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ where field.IsStatic

foreach (var property in properties)
{
var propertyTypeName = GetFullyQualifiedType(property.Type);
var propertyTypeName = property.Type.GetFullyQualifiedType();
var propertyName = property.Name;

if (IsStringIndexer(property))
Expand Down Expand Up @@ -505,23 +505,6 @@ where field.IsStatic
writer.AppendLine();
}

private object GetFullyQualifiedType(ITypeSymbol type)
{
if(type is INamedTypeSymbol namedTypeSymbol)
{
if (namedTypeSymbol.IsGenericType && !namedTypeSymbol.IsNullable())
{
return SymbolDisplay.ToDisplayString(type, format: new SymbolDisplayFormat(
globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included,
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
genericsOptions: SymbolDisplayGenericsOptions.None,
miscellaneousOptions: SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers))
+ "<" + string.Join(", ", namedTypeSymbol.TypeArguments.Select(GetFullyQualifiedType)) + ">";
}
}

return type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
}

private static string ExpandType(INamedTypeSymbol ownerType)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ namespace Microsoft.CodeAnalysis
/// </summary>
internal static class SymbolExtensions
{
private static bool IsRoslyn34OrEalier { get; }
= typeof(INamedTypeSymbol).Assembly.GetVersionNumber() <= new Version("3.4");

public static IEnumerable<IPropertySymbol> GetProperties(this INamedTypeSymbol symbol) => symbol.GetMembers().OfType<IPropertySymbol>();

public static IEnumerable<IEventSymbol> GetAllEvents(this INamedTypeSymbol symbol)
Expand Down Expand Up @@ -461,5 +464,27 @@ public static IFieldSymbol FindField(this INamedTypeSymbol symbol, INamedTypeSym
{
return symbol.GetFields().FirstOrDefault(x => Equals(x.Type, fieldType) && x.Name.Equals(fieldName, comparison));
}

/// <summary>
/// Builds a fully qualified type string, including generic types.
/// </summary>
public static string GetFullyQualifiedType(this ITypeSymbol type)
{
if (IsRoslyn34OrEalier && type is INamedTypeSymbol namedTypeSymbol)
{
if (namedTypeSymbol.IsGenericType && !namedTypeSymbol.IsNullable())
{
var typeName = Microsoft.CodeAnalysis.CSharp.SymbolDisplay.ToDisplayString(type, format: new SymbolDisplayFormat(
globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included,
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
genericsOptions: SymbolDisplayGenericsOptions.None,
miscellaneousOptions: SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers));

return typeName + "<" + string.Join(", ", namedTypeSymbol.TypeArguments.Select(GetFullyQualifiedType)) + ">";
}
}

return type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
}
}
}

0 comments on commit c7bebb2

Please sign in to comment.