Skip to content

Commit

Permalink
housekeeping: Diagnostics and Refactorings (#6)
Browse files Browse the repository at this point in the history
* NameDirectiveTransformer.cs
* Build-time diagnostics
  • Loading branch information
worldbeater authored Oct 27, 2020
1 parent b45c450 commit e3490c6
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public static MiniCompiler CreateDefault(RoslynTypeSystem typeSystem)
private MiniCompiler(TransformerConfiguration configuration)
: base(configuration, new XamlLanguageEmitMappings<object, IXamlEmitResult>(), false)
{
Transformers.Add(new NameDirectiveTransformer());
Transformers.Add(new KnownDirectivesTransformer());
Transformers.Add(new XamlIntrinsicsTransformer());
Transformers.Add(new XArgumentsTransformer());
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using XamlX;
using XamlX.Ast;
using XamlX.Transform;

namespace XamlNameReferenceGenerator.Infrastructure
{
public class NameDirectiveTransformer : IXamlAstTransformer
{
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
{
if (node is XamlAstObjectNode objectNode)
{
for (var index = 0; index < objectNode.Children.Count; index++)
{
var child = objectNode.Children[index];
if (child is XamlAstXmlDirective directive &&
directive.Namespace == XamlNamespaces.Xaml2006 &&
directive.Name == "Name")
objectNode.Children[index] = new XamlAstXamlPropertyValueNode(
directive,
new XamlAstNamePropertyReference(directive, objectNode.Type, "Name", objectNode.Type),
directive.Values);
}
}

return node;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System.Collections.Generic;
using XamlX.Ast;

namespace XamlNameReferenceGenerator.Infrastructure
{
internal sealed class NamedControlCollector : IXamlAstVisitor
{
private readonly List<(string TypeName, string Name)> _items = new List<(string TypeName, string Name)>();

public IReadOnlyList<(string TypeName, string Name)> Controls => _items;

public IXamlAstNode Visit(IXamlAstNode node)
{
if (node is XamlAstConstructableObjectNode constructableObjectNode)
{
foreach (var child in constructableObjectNode.Children)
{
if (child is XamlAstXamlPropertyValueNode propertyValueNode &&
propertyValueNode.Property is XamlAstClrProperty clrProperty &&
clrProperty.Name == "Name" &&
propertyValueNode.Values.Count > 0 &&
propertyValueNode.Values[0] is XamlAstTextNode text)
{
var clrType = constructableObjectNode.Type.GetClrType();
var typeNamePair = ($@"{clrType.Namespace}.{clrType.Name}", text.Text);

if (!_items.Contains(typeNamePair))
{
_items.Add(typeNamePair);
}
}
}

return node;
}

return node;
}

public void Push(IXamlAstNode node) { }

public void Pop() { }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,17 @@ public string Debug(Func<string> function)
if (File.Exists(_path))
File.Delete(_path);

string sourceCode;
try
{
sourceCode = function();
var sourceCode = function();
File.WriteAllText(_path, sourceCode);
return sourceCode;
}
catch (Exception exception)
{
File.WriteAllText(_path, exception.ToString());
sourceCode = string.Empty;
throw;
}

return sourceCode;
}
}
}
52 changes: 44 additions & 8 deletions src/XamlNameReferenceGenerator/NameReferenceGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
Expand Down Expand Up @@ -47,14 +48,49 @@ public void Execute(GeneratorExecutionContext context)
var symbols = UnpackAnnotatedTypes(compilation, receiver);
foreach (var typeSymbol in symbols)
{
var relevantXamlFile = context.AdditionalFiles
.First(text =>
text.Path.EndsWith($"{typeSymbol.Name}.xaml") ||
text.Path.EndsWith($"{typeSymbol.Name}.axaml"));
var xamlFileName = $"{typeSymbol.Name}.xaml";
var aXamlFileName = $"{typeSymbol.Name}.axaml";
var relevantXamlFile = context
.AdditionalFiles
.FirstOrDefault(text =>
text.Path.EndsWith(xamlFileName) ||
text.Path.EndsWith(aXamlFileName));

var sourceCode = Debugger.Debug(
() => GenerateSourceCode(xamlParser, typeSymbol, relevantXamlFile));
context.AddSource($"{typeSymbol.Name}.g.cs", SourceText.From(sourceCode, Encoding.UTF8));
if (relevantXamlFile is null)
{
context.ReportDiagnostic(
Diagnostic.Create(
new DiagnosticDescriptor(
"AXN0001",
"Unable to discover the relevant Avalonia XAML file.",
"Unable to discover the relevant Avalonia XAML file " +
$"neither at {xamlFileName} nor at {aXamlFileName}",
"Usage",
DiagnosticSeverity.Error,
true),
Location.None));
return;
}

try
{
var sourceCode = Debugger.Debug(() => GenerateSourceCode(xamlParser, typeSymbol, relevantXamlFile));
context.AddSource($"{typeSymbol.Name}.g.cs", SourceText.From(sourceCode, Encoding.UTF8));
}
catch (Exception exception)
{
context.ReportDiagnostic(
Diagnostic.Create(
new DiagnosticDescriptor(
"AXN0002",
"Unhandled exception occured while generating typed Name references.",
$"Unhandled exception occured while generating typed Name references: {exception}",
"Usage",
DiagnosticSeverity.Error,
true),
Location.None));
return;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ internal class XamlXNameReferenceXamlParser : INameReferenceXamlParser
.CreateDefault(new RoslynTypeSystem(_compilation))
.Transform(parsed);

var visitor = new MiniNamedControlCollector();
var visitor = new NamedControlCollector();
parsed.Root.Visit(visitor);
parsed.Root.VisitChildren(visitor);
return visitor.Controls;
Expand Down

0 comments on commit e3490c6

Please sign in to comment.