aboutsummaryrefslogtreecommitdiff
path: root/src/ext/Bal/WixToolset.Dnc.HostGenerator/DncHostGenerator.cs
blob: 088b2b493729a29cb6de78ffbf0d25cc8dfa7463 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.

namespace WixToolset.Dnc.HostGenerator
{
    using System;
    using System.Diagnostics.CodeAnalysis;
    using System.Text;
    using Microsoft.CodeAnalysis;
    using Microsoft.CodeAnalysis.Text;

    [Generator]
    public sealed class DncHostGenerator : ISourceGenerator
    {
        public static readonly string Version = String.Format($"{ThisAssembly.Git.SemVer.Major}.{ThisAssembly.Git.SemVer.Minor}.{ThisAssembly.Git.SemVer.Patch}{ThisAssembly.Git.SemVer.DashLabel}+{ThisAssembly.Git.Sha}");
        public static readonly string TargetAttributeFullName = "WixToolset.Mba.Core.BootstrapperApplicationFactoryAttribute";

        [SuppressMessage("MicrosoftCodeAnalysisReleaseTracking", "RS2008:Enable analyzer release tracking", Justification = "Tracking not needed")]
        public static readonly DiagnosticDescriptor MissingFactoryAttributeDescriptor = new DiagnosticDescriptor(
            "WIXBAL001",
            $"Missing assembly level attribute {TargetAttributeFullName}.",
            $"Add [assembly: {TargetAttributeFullName}(typeof(<your IBootstrapperApplicationFactory>)].",
            "WixToolset.Bal.wixext",
            DiagnosticSeverity.Error,
            true
        );

        public void Initialize(GeneratorInitializationContext context)
        {
        }

        public void Execute(GeneratorExecutionContext context)
        {
            var symbolDisplayFormat = new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces);

            string baFactoryClassName = null;
            foreach (var assemblyAttribute in context.Compilation.Assembly.GetAttributes())
            {
                var fullAssemblyTypeName = assemblyAttribute.AttributeClass.ToDisplayString(symbolDisplayFormat);

                if (fullAssemblyTypeName == TargetAttributeFullName &&
                    assemblyAttribute.ConstructorArguments.Length == 1)
                {
                    var arg = assemblyAttribute.ConstructorArguments[0];
                    if (arg.Value is INamedTypeSymbol argValue)
                    {
                        baFactoryClassName = argValue.ToDisplayString(symbolDisplayFormat);
                        break;
                    }
                }
            }

            if (baFactoryClassName == null)
            {
                context.ReportDiagnostic(Diagnostic.Create(MissingFactoryAttributeDescriptor, null));
            }
            else
            {
                var source = String.Format(Template, Version, baFactoryClassName);
                context.AddSource("WixToolset.Dnc.Host.g.cs", SourceText.From(source, Encoding.UTF8, SourceHashAlgorithm.Sha256));
            }
        }

        public const string Template = @"
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace WixToolset.Dnc.Host
{{
    using System;
    using System.CodeDom.Compiler;
    using System.Diagnostics.CodeAnalysis;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using WixToolset.Mba.Core;

    [GeneratedCode(""WixToolset.Dnc.HostGenerator.DncHostGenerator"", ""{0}"")]
    [CompilerGenerated]
    delegate IBootstrapperApplicationFactory StaticEntryDelegate();

    /// <summary>
    /// Entry point for the .NET Core host to create and return the BA to the engine.
    /// </summary>
    [GeneratedCode(""WixToolset.Dnc.HostGenerator.DncHostGenerator"", ""{0}"")]
    [CompilerGenerated]
    public sealed class BootstrapperApplicationFactory : IBootstrapperApplicationFactory
    {{
        /// <summary>
        /// Creates the bootstrapper application factory and calls its IBootstrapperApplicationFactory.Create method.
        /// </summary>
        /// <param name=""pArgs"">Pointer to BOOTSTRAPPER_CREATE_ARGS struct.</param>
        /// <param name=""pResults"">Pointer to BOOTSTRAPPER_CREATE_RESULTS struct.</param>
        public void Create(IntPtr pArgs, IntPtr pResults)
        {{
            var baFactory = new {1}();
            baFactory.Create(pArgs, pResults);
        }}

        // Entry point for the DNC host.
        public static IBootstrapperApplicationFactory CreateBAFactory()
        {{
            return new BootstrapperApplicationFactory();
        }}

#if NET5_0_OR_GREATER
        [ModuleInitializer]
        [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(BootstrapperApplicationFactory))]
#if NET5_0
        [DynamicDependency(""GetFunctionPointer(System.IntPtr,System.IntPtr,System.IntPtr,System.IntPtr,System.IntPtr,System.IntPtr)"", ""Internal.Runtime.InteropServices.ComponentActivator"", ""System.Private.CoreLib"")]
#endif
        /// <summary>
        /// Empty method to attach above attributes to support linker trimming.
        /// </summary>
        public static void ModuleInitialize() {{ }}
#endif
    }}
}}
";
    }
}