• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

loresoft / AssemblyMetadata.Generators / 11929967212

20 Nov 2024 08:57AM UTC coverage: 88.603%. First build
11929967212

Pull #103

github

web-flow
Merge da238c711 into 4dc0527be
Pull Request #103: Bump Microsoft.NET.Test.Sdk from 17.11.1 to 17.12.0

70 of 86 branches covered (81.4%)

Branch coverage included in aggregate %.

171 of 186 relevant lines covered (91.94%)

37.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.2
/src/AssemblyMetadata.Generators/AssemblyMetadataGenerator.cs
1
using System.Collections.Immutable;
2
using System.Reflection;
3
using System.Resources;
4
using System.Runtime.Versioning;
5

6
using Microsoft.CodeAnalysis;
7
using Microsoft.CodeAnalysis.CSharp;
8
using Microsoft.CodeAnalysis.CSharp.Syntax;
9

10
namespace AssemblyMetadata.Generators;
11

12
[Generator(LanguageNames.CSharp)]
13
public class AssemblyMetadataGenerator : IIncrementalGenerator
14
{
15
    private static readonly HashSet<string> _attributes =
1✔
16
    [
1✔
17
        nameof(AssemblyCompanyAttribute),
1✔
18
        nameof(AssemblyConfigurationAttribute),
1✔
19
        nameof(AssemblyCopyrightAttribute),
1✔
20
        nameof(AssemblyCultureAttribute),
1✔
21
        nameof(AssemblyDelaySignAttribute),
1✔
22
        nameof(AssemblyDescriptionAttribute),
1✔
23
        nameof(AssemblyFileVersionAttribute),
1✔
24
        nameof(AssemblyInformationalVersionAttribute),
1✔
25
        nameof(AssemblyKeyFileAttribute),
1✔
26
        nameof(AssemblyKeyNameAttribute),
1✔
27
        nameof(AssemblyMetadataAttribute),
1✔
28
        nameof(AssemblyProductAttribute),
1✔
29
        nameof(AssemblySignatureKeyAttribute),
1✔
30
        nameof(AssemblyTitleAttribute),
1✔
31
        nameof(AssemblyTrademarkAttribute),
1✔
32
        nameof(AssemblyVersionAttribute),
1✔
33
        nameof(NeutralResourcesLanguageAttribute),
1✔
34
        nameof(TargetFrameworkAttribute),
1✔
35
        "UserSecretsIdAttribute"
1✔
36
    ];
1✔
37

38
    public void Initialize(IncrementalGeneratorInitializationContext context)
39
    {
40

41
        var provider = context.SyntaxProvider
2✔
42
            .ForAttributeWithMetadataName(
2✔
43
                fullyQualifiedMetadataName: "System.Reflection.AssemblyVersionAttribute",
2✔
44
                predicate: SyntacticPredicate,
2✔
45
                transform: SemanticTransform
2✔
46
            )
2✔
47
            .Where(static context => context is not null);
4✔
48

49
        var diagnostics = provider
2✔
50
            .Select(static (item, _) => item.Diagnostics)
2✔
51
            .Where(static item => item.Count > 0);
4✔
52

53
        context.RegisterSourceOutput(diagnostics, ReportDiagnostic);
2✔
54

55
        var constants = provider
2✔
56
            .Select(static (item, _) => item.Constants)
2✔
57
            .Where(static item => item.Count > 0);
4✔
58

59
        var assemblyName = context.CompilationProvider
2✔
60
            .Select(static (c, _) => c.AssemblyName);
4✔
61

62
        var globalOptions = context.AnalyzerConfigOptionsProvider
2✔
63
            .Select(static (c, _) =>
2✔
64
            {
2✔
65
                c.GlobalOptions.TryGetValue("build_property.AssemblyName", out var assemblyName);
2✔
66
                c.GlobalOptions.TryGetValue("build_property.DefineConstants", out var defineConstants);
2✔
67
                c.GlobalOptions.TryGetValue("build_property.RootNamespace", out var rootNamespace);
2✔
68
                c.GlobalOptions.TryGetValue("build_property.ThisAssemblyNamespace", out var thisNamespace);
2✔
69

2✔
70
                var globalOptions = new GlobalOptions(
2✔
71
                    AssemblyName: assemblyName,
2✔
72
                    DefineConstants: defineConstants,
2✔
73
                    RootNamespace: rootNamespace,
2✔
74
                    ThisAssemblyNamespace: thisNamespace);
2✔
75

2✔
76
                return globalOptions;
2✔
77
            });
2✔
78

79
        var options = assemblyName.Combine(globalOptions);
2✔
80

81
        context.RegisterSourceOutput(constants.Combine(options), GenerateOutput);
2✔
82
    }
2✔
83

84
    private static bool SyntacticPredicate(SyntaxNode syntaxNode, CancellationToken cancellationToken)
85
    {
86
        // only want assembly level attributes
87
        return syntaxNode is CompilationUnitSyntax;
2✔
88
    }
89

90
    private static GeneratorContext SemanticTransform(GeneratorAttributeSyntaxContext context, CancellationToken cancellationToken)
91
    {
92
        var attributes = context.TargetSymbol.GetAttributes();
2✔
93
        var constants = new List<AssemblyConstant>();
2✔
94

95
        foreach (var attribute in attributes)
68✔
96
        {
97
            var name = attribute.AttributeClass?.Name;
32!
98
            if (name == null || !_attributes.Contains(name))
32✔
99
                continue;
100

101
            if (attribute.ConstructorArguments.Length == 1)
31✔
102
            {
103
                // remove Assembly
104
                if (name.Length > 8 && name.StartsWith("Assembly"))
21✔
105
                    name = name.Substring(8);
17✔
106

107
                // remove Attribute
108
                if (name.Length > 9)
21✔
109
                    name = name.Substring(0, name.Length - 9);
21✔
110

111
                var argument = attribute.ConstructorArguments.FirstOrDefault();
21✔
112
                var value = argument.ToCSharpString() ?? string.Empty;
21!
113

114
                if (string.IsNullOrWhiteSpace(value))
21✔
115
                    continue;
116

117
                var constant = new AssemblyConstant(name, value);
21✔
118
                constants.Add(constant);
21✔
119
            }
120
            else if (name == nameof(AssemblyMetadataAttribute) && attribute.ConstructorArguments.Length == 2)
10✔
121
            {
122
                var nameArgument = attribute.ConstructorArguments[0];
10✔
123
                var key = nameArgument.Value?.ToString() ?? string.Empty;
10!
124

125
                var valueArgument = attribute.ConstructorArguments[1];
10✔
126
                var value = valueArgument.ToCSharpString() ?? string.Empty;
10!
127

128
                if (string.IsNullOrWhiteSpace(key) || string.IsNullOrWhiteSpace(value))
10✔
129
                    continue;
130

131
                // prevent duplicates
132
                if (constants.Any(c => c.Name == key))
49✔
133
                    continue;
134

135
                var constant = new AssemblyConstant(key, value);
9✔
136
                constants.Add(constant);
9✔
137
            }
138
        }
139

140
        return new GeneratorContext([], constants);
2✔
141
    }
142

143
    private static void ReportDiagnostic(SourceProductionContext context, EquatableArray<Diagnostic> diagnostics)
144
    {
145
        foreach (var diagnostic in diagnostics)
×
146
            context.ReportDiagnostic(diagnostic);
×
147
    }
×
148

149
    private void GenerateOutput(SourceProductionContext context, (EquatableArray<AssemblyConstant> constants, (string? assemblyName, GlobalOptions globalOptions) options) parameters)
150
    {
151

152
        var constants = new List<AssemblyConstant>(parameters.constants);
2✔
153

154
        if (!constants.Any(p => p.Name == nameof(GlobalOptions.AssemblyName)))
32✔
155
        {
156
            var assemblyName = parameters.options.globalOptions.AssemblyName ?? parameters.options.assemblyName ?? string.Empty;
2!
157
            constants.Add(new AssemblyConstant(nameof(GlobalOptions.AssemblyName), $"\"{assemblyName}\""));
2✔
158
        }
159

160
        if (!constants.Any(p => p.Name == nameof(GlobalOptions.DefineConstants)))
34✔
161
        {
162
            var defineConstants = parameters.options.globalOptions.DefineConstants;
2✔
163
            if (!string.IsNullOrEmpty(defineConstants))
2!
164
                constants.Add(new AssemblyConstant(nameof(GlobalOptions.DefineConstants), $"\"{defineConstants}\""!));
×
165
        }
166

167
        if (!constants.Any(p => p.Name == nameof(GlobalOptions.RootNamespace)))
34✔
168
        {
169
            var rootNamespace = parameters.options.globalOptions.RootNamespace;
2✔
170
            if (!string.IsNullOrEmpty(rootNamespace))
2!
171
                constants.Add(new AssemblyConstant(nameof(GlobalOptions.RootNamespace), $"\"{rootNamespace}\""!));
×
172
        }
173

174
        var source = AssemblyMetadataWriter.Generate(constants, parameters.options.globalOptions.ThisAssemblyNamespace);
2✔
175

176
        context.AddSource("AssemblyMetadata.g.cs", source);
2✔
177
    }
2✔
178
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc