This repository has been archived by the owner on Jan 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 169
/
Copy pathMetadataGeneration.cs
87 lines (82 loc) · 4.08 KB
/
MetadataGeneration.cs
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
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.Quantum.QsCompiler.ReservedKeywords;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
namespace Microsoft.Quantum.QsCompiler
{
/// <summary>
/// The sole purpose of this module is to generate a C# class that explicitly uses referenced Q# content.
/// This is a hack to force that these references are not dropped upon Emit due to being unused.
/// This is needed (only) if we want to build dlls using the command line compiler without relying on the dotnet core project system.
/// </summary>
internal static class MetadataGeneration
{
public static ArrayTypeSyntax WithOmittedRankSpecifiers(this ArrayTypeSyntax syntax) =>
syntax.WithRankSpecifiers(
SingletonList(
ArrayRankSpecifier(
SingletonSeparatedList<ExpressionSyntax>(
OmittedArraySizeExpression()))));
internal static CodeAnalysis.SyntaxTree GenerateAssemblyMetadata(IEnumerable<MetadataReference> references)
{
var aliases = references
.Select(reference => reference.Properties.Aliases.FirstOrDefault(alias => alias.StartsWith(DotnetCoreDll.ReferenceAlias))) // FIXME: improve...
.Where(alias => alias != null);
var typeName =
QualifiedName(
AliasQualifiedName(
IdentifierName(Token(SyntaxKind.GlobalKeyword)),
IdentifierName("System")),
IdentifierName("Type"));
var metadataTypeNodes =
aliases.Select(alias =>
TypeOfExpression(
QualifiedName(
AliasQualifiedName(IdentifierName(alias), IdentifierName(DotnetCoreDll.MetadataNamespace)),
IdentifierName(DotnetCoreDll.MetadataType))));
var dependenciesInitializer =
ArrayCreationExpression(
ArrayType(typeName).WithOmittedRankSpecifiers())
.WithInitializer(
InitializerExpression(
SyntaxKind.ArrayInitializerExpression,
SeparatedList<ExpressionSyntax>(metadataTypeNodes)));
var metadataField =
FieldDeclaration(
VariableDeclaration(
ArrayType(typeName).WithOmittedRankSpecifiers())
.WithVariables(
SingletonSeparatedList(
VariableDeclarator(Identifier(DotnetCoreDll.Dependencies))
.WithInitializer(
EqualsValueClause(dependenciesInitializer)))))
.WithModifiers(
TokenList(
Token(SyntaxKind.PublicKeyword),
Token(SyntaxKind.StaticKeyword),
Token(SyntaxKind.ReadOnlyKeyword)));
var classDef =
ClassDeclaration(DotnetCoreDll.MetadataType)
.WithModifiers(
TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)))
.WithMembers(
SingletonList<MemberDeclarationSyntax>(metadataField));
var namespaceDef =
NamespaceDeclaration(IdentifierName(DotnetCoreDll.MetadataNamespace))
.WithMembers(
SingletonList<MemberDeclarationSyntax>(classDef));
var compilation =
CompilationUnit()
.WithExterns(
List(aliases.Select(Identifier).Select(ExternAliasDirective)))
.WithMembers(
SingletonList<MemberDeclarationSyntax>(namespaceDef));
return CSharpSyntaxTree.Create(compilation);
}
}
}