-
Notifications
You must be signed in to change notification settings - Fork 544
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Remove reflection usage for creating parts and root elements (#1240)
- Loading branch information
1 parent
1cf27c1
commit e224ff5
Showing
11 changed files
with
219 additions
and
144 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
135 changes: 135 additions & 0 deletions
135
gen/DocumentFormat.OpenXml.Generator/FactoryGenerator.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
using DocumentFormat.OpenXml.Generator.Editor; | ||
using DocumentFormat.OpenXml.Generator.Generators.Parts; | ||
using Microsoft.CodeAnalysis; | ||
using System.CodeDom.Compiler; | ||
using System.Text; | ||
|
||
namespace DocumentFormat.OpenXml.Generator; | ||
|
||
[Generator] | ||
public class FactoryGenerator : IIncrementalGenerator | ||
{ | ||
public void Initialize(IncrementalGeneratorInitializationContext context) | ||
{ | ||
var openXml = context.GetOpenXmlGeneratorContext() | ||
.GetOpenXmlServices(); | ||
|
||
context.RegisterSourceOutput(openXml, (context, openXml) => | ||
{ | ||
GeneratePartFactory(context, openXml); | ||
GenerateRootActivator(context, openXml); | ||
}); | ||
} | ||
|
||
private static void GeneratePartFactory(SourceProductionContext context, OpenXmlGeneratorServices openXml) | ||
{ | ||
using var sw = new StringWriter(); | ||
using var writer = new IndentedTextWriter(sw); | ||
|
||
writer.WriteFileHeader(); | ||
|
||
writer.WriteLine("using DocumentFormat.OpenXml;"); | ||
writer.WriteLine("using DocumentFormat.OpenXml.Packaging;"); | ||
writer.WriteLine(); | ||
writer.WriteLine("namespace DocumentFormat.OpenXml.Features;"); | ||
|
||
writer.WriteLine("internal partial class TypedPartFactory : IPartFactory"); | ||
|
||
using (writer.AddBlock()) | ||
{ | ||
writer.WriteLine("public T? Create<T>() where T : OpenXmlPart"); | ||
|
||
using (writer.AddBlock()) | ||
{ | ||
foreach (var part in openXml.Context.Parts) | ||
{ | ||
writer.Write("if (typeof(T) == typeof("); | ||
writer.Write(part.Name); | ||
writer.WriteLine("))"); | ||
|
||
using (writer.AddBlock()) | ||
{ | ||
writer.Write("return (T)(object)new "); | ||
writer.Write(part.Name); | ||
writer.WriteLine("();"); | ||
} | ||
|
||
writer.WriteLine(); | ||
} | ||
|
||
writer.WriteLine("return default;"); | ||
} | ||
} | ||
|
||
context.AddSource("TypedPartFactory", sw.ToString()); | ||
} | ||
|
||
private static void GenerateRootActivator(SourceProductionContext context, OpenXmlGeneratorServices openXml) | ||
{ | ||
using var sw = new StringWriter(); | ||
using var writer = new IndentedTextWriter(sw); | ||
|
||
writer.WriteFileHeader(); | ||
|
||
writer.WriteLine("using System;"); | ||
writer.WriteLine("using System.Collections.Generic;"); | ||
writer.WriteLine("using DocumentFormat.OpenXml;"); | ||
writer.WriteLine("using DocumentFormat.OpenXml.Packaging;"); | ||
writer.WriteLine("using DocumentFormat.OpenXml.Framework.Metadata;"); | ||
writer.WriteLine(); | ||
writer.WriteLine("namespace DocumentFormat.OpenXml.Features;"); | ||
|
||
writer.WriteLine("internal partial class TypedRootElementFactory : IRootElementFactory"); | ||
|
||
using (writer.AddBlock()) | ||
{ | ||
writer.WriteLine("public static IEnumerable<ElementFactory> GetAllRootElements()"); | ||
|
||
using (writer.AddBlock()) | ||
{ | ||
foreach (var model in openXml.Context.Namespaces) | ||
{ | ||
foreach (var type in model.Types) | ||
{ | ||
if (type.IsRootElement) | ||
{ | ||
var className = openXml.FindClassName(type.Name, fullyQualified: true); | ||
|
||
writer.Write("yield return new ElementFactory(typeof("); | ||
writer.Write(className); | ||
writer.Write("), new("); | ||
writer.WriteString(openXml.GetNamespaceInfo(type.Name.QName.Prefix).Uri); | ||
writer.Write(", "); | ||
writer.WriteString(type.Name.QName.Name); | ||
writer.Write("), () => new "); | ||
writer.Write(className); | ||
writer.WriteLine("());"); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
context.AddSource("TypedRootFactory", sw.ToString()); | ||
} | ||
|
||
private static void WritePartFiles(SourceProductionContext context, OpenXmlGeneratorServices openXml) | ||
{ | ||
var sb = new StringBuilder(); | ||
var sw = new StringWriter(sb); | ||
var writer = new IndentedTextWriter(sw); | ||
|
||
foreach (var part in openXml.Context.Parts) | ||
{ | ||
sb.Clear(); | ||
|
||
writer.WriteFileHeader(); | ||
writer.WritePart(openXml, part); | ||
|
||
context.AddSource(part.Name, sb.ToString()); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
72 changes: 0 additions & 72 deletions
72
src/DocumentFormat.OpenXml/Features/ReflectionBasedRootElementFactory.cs
This file was deleted.
Oops, something went wrong.
17 changes: 0 additions & 17 deletions
17
src/DocumentFormat.OpenXml/Features/ReflectionPartFactory.cs
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
src/DocumentFormat.OpenXml/Features/TypedRootElementFactory.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
using DocumentFormat.OpenXml.Framework; | ||
using DocumentFormat.OpenXml.Framework.Metadata; | ||
using System; | ||
using System.Diagnostics.CodeAnalysis; | ||
|
||
namespace DocumentFormat.OpenXml.Features; | ||
|
||
internal partial class TypedRootElementFactory : IRootElementFactory | ||
{ | ||
private readonly Lazy<ElementFactoryCollection> _collection; | ||
|
||
public TypedRootElementFactory() | ||
{ | ||
_collection = new Lazy<ElementFactoryCollection>(() => new ElementFactoryCollection(GetAllRootElements())); | ||
} | ||
|
||
public ElementFactoryCollection Collection => _collection.Value; | ||
|
||
public bool TryCreate(in OpenXmlQualifiedName qname, [NotNullWhen(true)] out OpenXmlElement? element) | ||
{ | ||
element = _collection.Value.Create(in qname); | ||
return element is not null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.