Skip to content

Commit

Permalink
feat: add automatic addition of registerattribute to nsobject subtypes
Browse files Browse the repository at this point in the history
  • Loading branch information
rdavisau committed Nov 13, 2022
1 parent ed796f1 commit 815e5a0
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 5 deletions.
Expand Up @@ -12,6 +12,7 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.Extensions.Logging;
using Roslyn.Reflection;
using Tbc.Core.Models;
using Tbc.Host.Components.Abstractions;
using Tbc.Host.Components.CommandProcessor.Models;
Expand Down Expand Up @@ -122,10 +123,6 @@ public EmittedAssembly StageFile(ChangedFile file, bool silent = false)
{
var sw = Stopwatch.StartNew();

file.Contents = file.Contents.Replace(
"_MYGUID_MYGUID_MYGUID_MYGUID_MYGUID_",
Guid.NewGuid().ToString().Replace("-", "_"));

var syntaxTree =
CSharpSyntaxTree.ParseText(
file.Contents,
Expand Down Expand Up @@ -174,7 +171,25 @@ public EmittedAssembly StageFile(ChangedFile file, bool silent = false)
}
var compilation = (CSharpCompilation)(sourceGeneratedCompilation ?? newCompilation);
var result = EmitAssembly(sourceGeneratedCompilation ?? newCompilation, out emittedAssembly);
if (_options.iOSDynamicRegistrationOptions.Enabled)
{
var dynamicRegistrationCompilation = compilation;
foreach (var tree in compilation.SyntaxTrees)
{
var rewriter = new iOSDynamicRegistrationAttributeRewriter(
new MetadataLoadContext(dynamicRegistrationCompilation),
dynamicRegistrationCompilation.GetSemanticModel(tree, ignoreAccessibility: true)
);
dynamicRegistrationCompilation = dynamicRegistrationCompilation
.ReplaceSyntaxTree(tree, SyntaxFactory.SyntaxTree(rewriter.Visit(tree.GetRoot()), tree.Options, tree.FilePath, tree.Encoding));
}
compilation = dynamicRegistrationCompilation;
}
var result = EmitAssembly(compilation, out emittedAssembly);
if (!result.Success
&& _options.FixerOptions.Enabled
Expand Down
@@ -0,0 +1,56 @@
using System;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Reflection;

namespace Tbc.Host.Components.IncrementalCompiler;

// adds a unique [Register] attribute to every nsobject-derived type
public class iOSDynamicRegistrationAttributeRewriter : CSharpSyntaxRewriter
{
private readonly MetadataLoadContext _metadataLoadContext;
private readonly SemanticModel _semanticModel;
private readonly Type _nsObject;

public iOSDynamicRegistrationAttributeRewriter(MetadataLoadContext metadataLoadContext, SemanticModel semanticModel)
{
_metadataLoadContext = metadataLoadContext;
_semanticModel = semanticModel;

_nsObject = _metadataLoadContext.ResolveType("Foundation.NSObject");
}

public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)
{
var symbol = _semanticModel.GetDeclaredSymbolForNode(node);
if (symbol is null) return base.VisitClassDeclaration(node);

var symbolReference = $"{symbol.ContainingNamespace}.{symbol.MetadataName}";
var type = _metadataLoadContext.ResolveType(symbolReference);
if (type is null)
return base.VisitClassDeclaration(node);

if (type.IsSubclassOf(_nsObject))
{
var attributeArgument =
SyntaxFactory.AttributeList
(SyntaxFactory.SingletonSeparatedList(
SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("Register"),
SyntaxFactory.AttributeArgumentList(
SyntaxFactory.SeparatedList(new[] {
SyntaxFactory.AttributeArgument(
SyntaxFactory.LiteralExpression(
SyntaxKind.StringLiteralExpression,
SyntaxFactory.Literal($"{symbol.MetadataName}_{Guid.NewGuid()}"))
)
})))));

var updatedNode = node.WithAttributeLists(node.AttributeLists.Add(attributeArgument));

return updatedNode;
}

return base.VisitClassDeclaration(node);
}
}
Expand Up @@ -17,5 +17,6 @@ public class AssemblyCompilationOptions
public List<SourceGeneratorReference> SourceGeneratorReferences { get; set; } = new();
public List<GlobalUsingsSource> GlobalUsingsSources { get; set; } = new();
public AssemblyFixerOptions FixerOptions { get; set; } = new() { Enabled = true };
public iOSDynamicRegistrationOptions iOSDynamicRegistrationOptions { get; set; } = new();
}
}
@@ -0,0 +1,6 @@
namespace Tbc.Host.Config;

public class iOSDynamicRegistrationOptions
{
public bool Enabled { get; set; }
}

0 comments on commit 815e5a0

Please sign in to comment.