Skip to content

Commit

Permalink
fix: resolve namespace conflicts in generated code
Browse files Browse the repository at this point in the history
  • Loading branch information
jonisavo committed Oct 23, 2022
1 parent b53523b commit a1eb455
Show file tree
Hide file tree
Showing 12 changed files with 165 additions and 17 deletions.
Binary file modified Assets/UIComponents/Roslyn/UIComponents.Roslyn.Generation.dll
Binary file not shown.
Binary file modified Assets/UIComponents/Roslyn/UIComponents.Roslyn.Generation.pdb
Binary file not shown.
1 change: 1 addition & 0 deletions UIComponents.Roslyn/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TestResults/
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,31 @@ private partial class NestedProvideComponent : UIComponent
return GeneratorTester.Verify<ProvideAugmentGenerator>(source);
}

[Fact]
public Task It_Handles_Common_Namespaces()
{
var firstSource = @"
namespace MyLibrary.Core.Services
{
public interface IService {}
}
";
var secondSource = @"
using UIComponents;
using MyLibrary.Core.Services;
namespace MyLibrary.GUI
{
public class GuiComponent
{
[Provide]
public IService service;
}
}
";
return GeneratorTester.Verify<ProvideAugmentGenerator>(firstSource, secondSource);
}

[Fact]
public Task It_Does_Not_Generate_For_Non_Interface_Or_Class_Fields()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,33 @@ public partial class MultipleQueryComponent : UIComponent
return GeneratorTester.Verify<QueryAugmentGenerator>(source);
}

[Fact]
public Task It_Handles_Common_Namespaces()
{
var firstSource = @"
using UnityEngine.UIElements;
namespace MyLibrary.Core.Elements;
{
public class MyElement : VisualElement {}
}
";
var secondSource = @"
using UIComponents;
using MyLibrary.Core.Elements;
namespace MyLibrary.GUI
{
public class MyComponent : UIComponent
{
[Query]
public MyElement element;
}
}
";
return GeneratorTester.Verify<QueryAugmentGenerator>(firstSource, secondSource);
}

[Fact]
public Task Does_Not_Generate_If_No_Queries_Exist()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//HintName: GuiComponent.Provide.g.cs
// <auto-generated>
// This file has been generated automatically by UIComponents.Roslyn.
// Do not attempt to modify it. Any changes will be overridden during compilation.
// </auto-generated>

using System;
using UIComponents;
using System.CodeDom.Compiler;
using UnityEngine.UIElements;

namespace MyLibrary.GUI
{
public partial class GuiComponent
{
[GeneratedCode("UIComponents.Roslyn.Generation", "1.0.0-alpha.1")]
private void UIC_SetProvideField<TField, TCastFrom>(ref TField value, string fieldName) where TField : class where TCastFrom : class
{
try
{
value = (TField) (object) Provide<TCastFrom>();
}
catch (MissingProviderException)
{
Logger.LogError($"Could not provide {typeof(TField).Name} to {fieldName}", this);
}
catch (InvalidCastException)
{
Logger.LogError($"Could not cast {typeof(TCastFrom).Name} to {typeof(TField).Name}", this);
}
}

[GeneratedCode("UIComponents.Roslyn.Generation", "1.0.0-alpha.1")]
protected override void UIC_PopulateProvideFields()
{
UIC_SetProvideField<Core.Services.IService, Core.Services.IService>(ref service, "service");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//HintName: MyComponent.Query.g.cs
// <auto-generated>
// This file has been generated automatically by UIComponents.Roslyn.
// Do not attempt to modify it. Any changes will be overridden during compilation.
// </auto-generated>

using System.Collections.Generic;
using System.CodeDom.Compiler;
using UnityEngine.UIElements;

namespace MyLibrary.GUI
{
public partial class MyComponent
{
[GeneratedCode("UIComponents.Roslyn.Generation", "1.0.0-alpha.1")]
protected override void UIC_PopulateQueryFields()
{
var UIC_elementList = new List<Core.Elements.MyElement>();
this.Query<Core.Elements.MyElement>(null, (string) null).ToList(UIC_elementList);
if (UIC_elementList.Count > 0)
element = UIC_elementList[0];
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ namespace UIComponents.Roslyn.Generation.Tests.Utilities
{
internal class GeneratorTester
{
public static Task Verify<TGenerator>(string source) where TGenerator : ISourceGenerator, new()
public static Task Verify<TGenerator>(params string[] sources) where TGenerator : ISourceGenerator, new()
{
var syntaxTree = CSharpSyntaxTree.ParseText(source);
var syntaxTrees = new SyntaxTree[sources.Length];

for (var i = 0; i < sources.Length; i++)
syntaxTrees[i] = CSharpSyntaxTree.ParseText(sources[i]);

var references = new[]
{
Expand All @@ -21,7 +24,7 @@ public static Task Verify<TGenerator>(string source) where TGenerator : ISourceG

var compilation = CSharpCompilation.Create(
assemblyName: "Tests",
syntaxTrees: new[] { syntaxTree },
syntaxTrees: syntaxTrees,
references: references
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,13 @@ protected override void UIC_PopulateProvideFields()

foreach (var provideDescription in _provideDescriptions)
{
var typeName =
RoslynUtilities.GetTypeNameWithoutRootNamespace(provideDescription.Field.Type, context.CurrentTypeNamespace);
stringBuilder
.Append(" UIC_SetProvideField<")
.Append(provideDescription.Field.Type.ToDisplayString())
.Append(typeName)
.Append(", ")
.Append(provideDescription.GetCastFromTypeName())
.Append(provideDescription.GetCastFromTypeName(context.CurrentTypeNamespace))
.Append(">(ref ")
.Append(provideDescription.Field.Name)
.Append(", ")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.CodeAnalysis;
using System;
using UIComponents.Roslyn.Generation.Utilities;

namespace UIComponents.Roslyn.Generation.Generators.DependencyInjection
{
Expand All @@ -14,12 +15,12 @@ public ProvideDescription(IFieldSymbol field, INamedTypeSymbol castFromType)
CastFromType = castFromType;
}

public string GetCastFromTypeName()
public string GetCastFromTypeName(string nameSpace)
{
if (CastFromType != null)
return CastFromType.ToDisplayString();
return RoslynUtilities.GetTypeNameWithoutRootNamespace(CastFromType, nameSpace);

return Field.Type.ToDisplayString();
return RoslynUtilities.GetTypeNameWithoutRootNamespace(Field.Type, nameSpace);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@ private void GenerateQueryAssignment(QueryDescription queryDescription, StringBu
var memberSymbol = queryDescription.MemberSymbol;
var memberType = RoslynUtilities.GetMemberType(memberSymbol);

var namespaceString = memberSymbol.ContainingNamespace.ToDisplayString();
var concreteMemberType = RoslynUtilities.GetConcreteType(memberType);
var concreteMemberTypeName = concreteMemberType.ToDisplayString();
var concreteMemberTypeName = RoslynUtilities.GetTypeNameWithoutRootNamespace(concreteMemberType, namespaceString);

const string Padding = " ";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,8 @@ internal static class RoslynUtilities
// https://andrewlock.net/creating-a-source-generator-part-5-finding-a-type-declarations-namespace-and-type-hierarchy/
public static string GetTypeNamespace(SyntaxNode syntaxNode)
{
if (syntaxNode == null)
return string.Empty;

var currentNamespace = string.Empty;

var potentialNamespaceParent = syntaxNode.Parent;

while (potentialNamespaceParent != null && !(potentialNamespaceParent is NamespaceDeclarationSyntax))
potentialNamespaceParent = potentialNamespaceParent.Parent;
var potentialNamespaceParent = GetNamespaceDeclaration(syntaxNode);

if (potentialNamespaceParent is NamespaceDeclarationSyntax namespaceParent)
{
Expand All @@ -36,6 +29,38 @@ public static string GetTypeNamespace(SyntaxNode syntaxNode)
return currentNamespace;
}

public static NamespaceDeclarationSyntax GetNamespaceDeclaration(SyntaxNode syntaxNode)
{
if (syntaxNode == null)
return null;

var potentialNamespaceParent = syntaxNode.Parent;

while (potentialNamespaceParent != null && !(potentialNamespaceParent is NamespaceDeclarationSyntax))
potentialNamespaceParent = potentialNamespaceParent.Parent;

return potentialNamespaceParent as NamespaceDeclarationSyntax;
}

public static string GetTypeNameWithoutRootNamespace(ITypeSymbol type, string nameSpace)
{
var displayString = type.ToDisplayString();

var namespaceParts = nameSpace.Split('.');

if (namespaceParts.Length < 2)
return displayString;

var rootNamespace = namespaceParts[0];

if (!displayString.StartsWith(rootNamespace))
return displayString;

var firstDotIndex = displayString.IndexOf('.') + 1;

return displayString.Substring(firstDotIndex);
}

public static BaseTypeDeclarationSyntax GetBaseTypeSyntax(SyntaxNode syntaxNode)
{
while (syntaxNode != null)
Expand Down

0 comments on commit a1eb455

Please sign in to comment.