Browse Source

housekeeping: Diagnostics and Refactorings (#6)

* NameDirectiveTransformer.cs
* Build-time diagnostics
pull/10407/head
Artyom V. Gorchakov 6 years ago
committed by GitHub
parent
commit
e3490c69d3
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      src/XamlNameReferenceGenerator/Infrastructure/MiniCompiler.cs
  2. 54
      src/XamlNameReferenceGenerator/Infrastructure/MiniNamedControlCollector.cs
  3. 29
      src/XamlNameReferenceGenerator/Infrastructure/NameDirectiveTransformer.cs
  4. 44
      src/XamlNameReferenceGenerator/Infrastructure/NamedControlCollector.cs
  5. 8
      src/XamlNameReferenceGenerator/Infrastructure/PhysicalFileDebugger.cs
  6. 52
      src/XamlNameReferenceGenerator/NameReferenceGenerator.cs
  7. 2
      src/XamlNameReferenceGenerator/Parsers/XamlXNameReferenceXamlParser.cs

1
src/XamlNameReferenceGenerator/Infrastructure/MiniCompiler.cs

@ -22,6 +22,7 @@ namespace XamlNameReferenceGenerator.Infrastructure
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());

54
src/XamlNameReferenceGenerator/Infrastructure/MiniNamedControlCollector.cs

@ -1,54 +0,0 @@
using System.Collections.Generic;
using XamlX.Ast;
namespace XamlNameReferenceGenerator.Infrastructure
{
internal sealed class MiniNamedControlCollector : 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))
return node;
foreach (var child in constructableObjectNode.Children)
{
var nameValue = ResolveNameDirectiveOrDefault(child);
if (nameValue == null) continue;
var clrType = constructableObjectNode.Type.GetClrType();
var typeNamePair = ($@"{clrType.Namespace}.{clrType.Name}", nameValue);
if (!_items.Contains(typeNamePair))
{
_items.Add(typeNamePair);
}
}
return node;
}
public void Push(IXamlAstNode node) { }
public void Pop() { }
private static string ResolveNameDirectiveOrDefault(IXamlAstNode node) =>
node switch
{
XamlAstXamlPropertyValueNode propertyValueNode when
propertyValueNode.Property is XamlAstClrProperty reference &&
reference.Name == "Name" &&
propertyValueNode.Values.Count > 0 &&
propertyValueNode.Values[0] is XamlAstTextNode nameNode => nameNode.Text,
XamlAstXmlDirective xmlDirective when
xmlDirective.Name == "Name" &&
xmlDirective.Values.Count > 0 &&
xmlDirective.Values[0] is XamlAstTextNode xNameNode => xNameNode.Text,
_ => null
};
}
}

29
src/XamlNameReferenceGenerator/Infrastructure/NameDirectiveTransformer.cs

@ -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;
}
}
}

44
src/XamlNameReferenceGenerator/Infrastructure/NamedControlCollector.cs

@ -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() { }
}
}

8
src/XamlNameReferenceGenerator/Infrastructure/PhysicalFileDebugger.cs

@ -15,19 +15,17 @@ namespace XamlNameReferenceGenerator.Infrastructure
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
src/XamlNameReferenceGenerator/NameReferenceGenerator.cs

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
@ -47,14 +48,49 @@ namespace XamlNameReferenceGenerator
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;
}
}
}

2
src/XamlNameReferenceGenerator/Parsers/XamlXNameReferenceXamlParser.cs

@ -23,7 +23,7 @@ namespace XamlNameReferenceGenerator.Parsers
.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;

Loading…
Cancel
Save