Skip to content

Commit 3fab0a1

Browse files
committed
Merge branch 'develop'
2 parents db7c63b + 750521d commit 3fab0a1

20 files changed

+685
-146
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using Microsoft.CodeAnalysis.CSharp.Syntax;
2+
using UnityUxmlGenerator.Extensions;
3+
4+
namespace UnityUxmlGenerator.Captures;
5+
6+
internal abstract class BaseCapture
7+
{
8+
protected BaseCapture(ClassDeclarationSyntax @class)
9+
{
10+
Class = @class;
11+
ClassName = @class.Identifier.Text;
12+
ClassNamespace = @class.GetParent<NamespaceDeclarationSyntax>()!.Name.ToString();
13+
}
14+
15+
public string ClassName { get; }
16+
public string ClassNamespace { get; }
17+
public abstract string ClassTag { get; }
18+
19+
public ClassDeclarationSyntax Class { get; }
20+
}
Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
11
using Microsoft.CodeAnalysis.CSharp.Syntax;
2-
using UnityUxmlGenerator.Extensions;
32

43
namespace UnityUxmlGenerator.Captures;
54

6-
internal sealed class UxmlFactoryCapture
5+
internal sealed class UxmlFactoryCapture : BaseCapture
76
{
8-
public UxmlFactoryCapture(ClassDeclarationSyntax @class)
7+
public UxmlFactoryCapture(ClassDeclarationSyntax @class) : base(@class)
98
{
10-
Class = @class;
11-
ClassName = @class.Identifier.Text;
12-
ClassNamespace = @class.GetParent<NamespaceDeclarationSyntax>()!.Name.ToString();
139
}
1410

15-
public string ClassName { get; }
16-
public string ClassNamespace { get; }
17-
18-
public ClassDeclarationSyntax Class { get; }
11+
public override string ClassTag => "UxmlFactory";
1912
}

src/UnityUxmlGenerator/Captures/UxmlTraitsCapture.cs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,19 @@
11
using Microsoft.CodeAnalysis.CSharp.Syntax;
2-
using UnityUxmlGenerator.Extensions;
32

43
namespace UnityUxmlGenerator.Captures;
54

6-
internal sealed class UxmlTraitsCapture
5+
internal sealed class UxmlTraitsCapture : BaseCapture
76
{
8-
public UxmlTraitsCapture(ClassDeclarationSyntax @class, TypeSyntax baseClassType)
7+
public UxmlTraitsCapture(ClassDeclarationSyntax @class, TypeSyntax baseClassType) : base(@class)
98
{
10-
Class = @class;
11-
ClassName = @class.Identifier.Text;
12-
ClassNamespace = @class.GetParent<NamespaceDeclarationSyntax>()!.Name.ToString();
13-
149
BaseClassType = baseClassType;
15-
Properties = new List<(string PropertyName, string? DefaultValue)>();
10+
Properties = new List<(PropertyDeclarationSyntax property, string? DefaultValue)>();
1611
}
1712

18-
public string ClassName { get; }
19-
public string ClassNamespace { get; }
13+
public override string ClassTag => "UxmlTraits";
2014

2115
public TypeSyntax BaseClassType { get; }
22-
public ClassDeclarationSyntax Class { get; }
23-
24-
public List<(string PropertyName, string? DefaultValue)> Properties { get; }
16+
public List<(PropertyDeclarationSyntax property, string? DefaultValue)> Properties { get; }
2517

2618
public string GetBaseClassName(out TypeSyntax? genericTypeSyntax)
2719
{
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using Microsoft.CodeAnalysis;
2+
3+
namespace UnityUxmlGenerator.Diagnostics;
4+
5+
internal static class DiagnosticDescriptors
6+
{
7+
public static readonly DiagnosticDescriptor ClassHasNoBaseClassError = new(
8+
id: "UXMLG001",
9+
title: "Class has no base class",
10+
messageFormat: "Class '{0}' must be declared as a partial and be inherited from 'VisualElement' or one of its derived classes.",
11+
category: typeof(UxmlGenerator).FullName,
12+
defaultSeverity: DiagnosticSeverity.Error,
13+
isEnabledByDefault: true);
14+
15+
public static readonly DiagnosticDescriptor ClassDoesNotInheritFromVisualElementError = new(
16+
id: "UXMLG002",
17+
title: "Class does not inherit from VisualElement",
18+
messageFormat: "Class '{0}' must be declared as a partial and be inherited from 'VisualElement' or one of its derived classes.",
19+
category: typeof(UxmlGenerator).FullName,
20+
defaultSeverity: DiagnosticSeverity.Error,
21+
isEnabledByDefault: true);
22+
23+
public static readonly DiagnosticDescriptor PropertyAndDefaultValueTypesMismatchError = new(
24+
id: "UXMLG003",
25+
title: "Types mismatch",
26+
messageFormat: "UxmlAttribute for '{0}' property was not created. The default property and attribute value must be of the same type.",
27+
category: typeof(UxmlGenerator).FullName,
28+
defaultSeverity: DiagnosticSeverity.Error,
29+
isEnabledByDefault: true);
30+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using Microsoft.CodeAnalysis;
2+
3+
namespace UnityUxmlGenerator.Diagnostics;
4+
5+
internal static class DiagnosticExtensions
6+
{
7+
public static Diagnostic CreateDiagnostic(this DiagnosticDescriptor descriptor, Location location, params object[] args)
8+
{
9+
return Diagnostic.Create(descriptor, location, args);
10+
}
11+
}

src/UnityUxmlGenerator/Extensions/BaseTypeDeclarationSyntaxExtensions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ namespace UnityUxmlGenerator.Extensions;
66

77
internal static class BaseTypeDeclarationSyntaxExtensions
88
{
9+
public static bool InheritsFromAnyType(this BaseTypeDeclarationSyntax? @class)
10+
{
11+
return @class?.BaseList is not null && @class.BaseList.Types.Count != 0;
12+
}
13+
914
public static bool InheritsFromFullyQualifiedName(this BaseTypeDeclarationSyntax @class,
1015
GeneratorExecutionContext context, string name)
1116
{
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using Microsoft.CodeAnalysis.CSharp.Syntax;
2+
3+
namespace UnityUxmlGenerator.Extensions;
4+
5+
internal static class PropertySyntaxExtensions
6+
{
7+
public static string GetName(this PropertyDeclarationSyntax property)
8+
{
9+
return property.Identifier.Text;
10+
}
11+
}

src/UnityUxmlGenerator/Extensions/StringExtensions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ namespace UnityUxmlGenerator.Extensions;
44

55
internal static class StringExtensions
66
{
7+
public static string FirstCharToUpper(this string str)
8+
{
9+
return $"{char.ToUpper(str[0])}{str.Substring(1)}";
10+
}
11+
712
public static string ToPrivateFieldName(this string propertyName)
813
{
914
return string.Concat("_", char.ToLower(propertyName[0]), propertyName.Substring(1));
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using Microsoft.CodeAnalysis.CSharp;
2+
using Microsoft.CodeAnalysis.CSharp.Syntax;
3+
4+
namespace UnityUxmlGenerator.Extensions;
5+
6+
internal static class TypeSyntaxExtensions
7+
{
8+
public static bool IsBoolType(this TypeSyntax typeSyntax)
9+
{
10+
if (typeSyntax is PredefinedTypeSyntax predefinedTypeSyntax)
11+
{
12+
return IsBoolType(predefinedTypeSyntax);
13+
}
14+
15+
return IsBoolKind(typeSyntax.RawKind);
16+
}
17+
18+
public static bool IsBoolType(this PredefinedTypeSyntax typeSyntax)
19+
{
20+
return IsBoolKind(typeSyntax.Keyword.RawKind);
21+
}
22+
23+
public static bool IsStringType(this TypeSyntax typeSyntax)
24+
{
25+
if (typeSyntax is PredefinedTypeSyntax predefinedTypeSyntax)
26+
{
27+
return IsStringType(predefinedTypeSyntax);
28+
}
29+
30+
return IsStringKind(typeSyntax.RawKind);
31+
}
32+
33+
public static bool IsStringType(this PredefinedTypeSyntax typeSyntax)
34+
{
35+
return IsStringKind(typeSyntax.Keyword.RawKind);
36+
}
37+
38+
public static bool IsNumericType(this TypeSyntax typeSyntax)
39+
{
40+
if (typeSyntax is PredefinedTypeSyntax predefinedTypeSyntax)
41+
{
42+
return IsNumericType(predefinedTypeSyntax);
43+
}
44+
45+
return IsNumericKind(typeSyntax.RawKind);
46+
}
47+
48+
public static bool IsNumericType(this PredefinedTypeSyntax typeSyntax)
49+
{
50+
return IsNumericKind(typeSyntax.Keyword.RawKind);
51+
}
52+
53+
private static bool IsBoolKind(int rawKind)
54+
{
55+
return rawKind == (int) SyntaxKind.BoolKeyword;
56+
}
57+
58+
private static bool IsStringKind(int rawKind)
59+
{
60+
return rawKind == (int) SyntaxKind.StringKeyword;
61+
}
62+
63+
private static bool IsNumericKind(int rawKind)
64+
{
65+
return rawKind == (int) SyntaxKind.IntKeyword ||
66+
rawKind == (int) SyntaxKind.LongKeyword ||
67+
rawKind == (int) SyntaxKind.FloatKeyword ||
68+
rawKind == (int) SyntaxKind.DoubleKeyword;
69+
}
70+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using Microsoft.CodeAnalysis.CSharp.Syntax;
2+
3+
namespace UnityUxmlGenerator.Structs;
4+
5+
public ref struct UxmlAttributeInfo
6+
{
7+
public string TypeIdentifier { get; set; }
8+
public string PrivateFieldName { get; set; }
9+
public string AttributeUxmlName { get; set; }
10+
public ExpressionSyntax DefaultValueAssignmentExpression { get; set; }
11+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using Microsoft.CodeAnalysis;
2+
using UnityUxmlGenerator.Diagnostics;
3+
4+
namespace UnityUxmlGenerator.SyntaxReceivers;
5+
6+
internal abstract class BaseReceiver : ISyntaxReceiver
7+
{
8+
private readonly List<Diagnostic> _diagnostics = new();
9+
10+
public IEnumerable<Diagnostic> Diagnostics => _diagnostics;
11+
12+
public abstract void OnVisitSyntaxNode(SyntaxNode syntaxNode);
13+
14+
protected void RegisterDiagnostic(DiagnosticDescriptor diagnosticDescriptor, Location location,
15+
params object[] args)
16+
{
17+
_diagnostics.Add(diagnosticDescriptor.CreateDiagnostic(location, args));
18+
}
19+
}

src/UnityUxmlGenerator/SyntaxReceivers/UxmlFactoryReceiver.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55

66
namespace UnityUxmlGenerator.SyntaxReceivers;
77

8-
internal sealed class UxmlFactoryReceiver : ISyntaxReceiver
8+
internal sealed class UxmlFactoryReceiver : BaseReceiver
99
{
1010
private const string AttributeName = "UxmlElement";
1111

1212
private readonly List<UxmlFactoryCapture> _captures = new();
1313

1414
public IEnumerable<UxmlFactoryCapture> Captures => _captures;
1515

16-
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
16+
public override void OnVisitSyntaxNode(SyntaxNode syntaxNode)
1717
{
1818
if (syntaxNode is not AttributeSyntax
1919
{
@@ -25,11 +25,13 @@ public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
2525

2626
var @class = attribute.GetParent<ClassDeclarationSyntax>();
2727

28-
if (@class?.BaseList is null || @class.BaseList.Types.Count == 0)
28+
if (@class.InheritsFromAnyType())
2929
{
30-
return;
30+
_captures.Add(new UxmlFactoryCapture(@class!));
31+
}
32+
else if (@class is not null)
33+
{
34+
RegisterDiagnostic(ClassHasNoBaseClassError, @class.GetLocation(), @class.Identifier.Text);
3135
}
32-
33-
_captures.Add(new UxmlFactoryCapture(@class));
3436
}
3537
}

0 commit comments

Comments
 (0)