From fae8f0754fbc54348abd60a199996809120161a6 Mon Sep 17 00:00:00 2001 From: Daniel Cazzulino Date: Fri, 13 Sep 2024 18:33:09 -0300 Subject: [PATCH] After grace period, emit code with warnings It was made quite clear that (some?) folks would rather just disable our friendly warning rather than sponsor. So we'll instead just make sponsorship mandatory. See https://github.com/devlooped/ThisAssembly/issues/352#issuecomment-2325054917 I worked hard to accomodate very flexible options for sponsoring, and this project ain't maintaining itself. It's fine if folks use something else. I made this initially just for myself, and I'm glad it's been useful for others. TODO: pending updating AssemblyInfo and Strings to use the same approach (those don't leverage Constants like the others). --- src/Directory.targets | 5 +++- src/Shared/EmbeddedResource.cs | 15 +++++++++- src/Shared/PathSanitizer.cs | 9 +++++- src/ThisAssembly.Constants/CSharp.sbntxt | 16 ++++++++-- .../ConstantsGenerator.cs | 30 +++++++++++-------- src/ThisAssembly.Constants/Model.cs | 2 +- src/ThisAssembly.Tests/Tests.cs | 6 ++-- .../ThisAssembly.Tests.csproj | 16 +++++++--- 8 files changed, 73 insertions(+), 26 deletions(-) diff --git a/src/Directory.targets b/src/Directory.targets index 190069e0..d2a8362b 100644 --- a/src/Directory.targets +++ b/src/Directory.targets @@ -5,6 +5,7 @@ > This project uses SponsorLink and may issue IDE-only warnings if no active sponsorship is detected. Learn more at https://github.com/devlooped#sponsorlink. + $(PackFolder.StartsWith('analyzers/')) @@ -12,12 +13,14 @@ + + - + + /// Gets the content of the embedded resource at the specified relative path. + /// public static string GetContent(string relativePath) { using var stream = GetStream(relativePath); @@ -17,6 +23,9 @@ public static string GetContent(string relativePath) return reader.ReadToEnd(); } + /// + /// Gets the bytes of the embedded resource at the specified relative path. + /// public static byte[] GetBytes(string relativePath) { using var stream = GetStream(relativePath); @@ -25,6 +34,10 @@ public static byte[] GetBytes(string relativePath) return bytes; } + /// + /// Gets the stream of the embedded resource at the specified relative path. + /// + /// public static Stream GetStream(string relativePath) { #if DEBUG diff --git a/src/Shared/PathSanitizer.cs b/src/Shared/PathSanitizer.cs index 992cda7b..ff8b0d29 100644 --- a/src/Shared/PathSanitizer.cs +++ b/src/Shared/PathSanitizer.cs @@ -1,8 +1,15 @@ using System.Text.RegularExpressions; -static class PathSanitizer +/// +/// Sanitizes paths for use as identifiers. +/// +public static class PathSanitizer { static readonly Regex invalidCharsRegex = new(@"\W"); + + /// + /// Sanitizes the specified path for use as an identifier. + /// public static string Sanitize(string path, string parent) { var partStr = invalidCharsRegex.Replace(path, "_"); diff --git a/src/ThisAssembly.Constants/CSharp.sbntxt b/src/ThisAssembly.Constants/CSharp.sbntxt index a5af0287..ad8aefda 100644 --- a/src/ThisAssembly.Constants/CSharp.sbntxt +++ b/src/ThisAssembly.Constants/CSharp.sbntxt @@ -8,7 +8,7 @@ // the code is regenerated. // //------------------------------------------------------------------------------ -{{ func summary }} +{{- func summary -}} /// {{~ if $0.Comment ~}} /// {{ $0.Comment }} @@ -16,12 +16,24 @@ /// => @"{{ $0.Value }}" {{~ end ~}} /// +{{- end -}} +{{ func obsolete }} +{{ WarnSummary }} +[Obsolete("{{ Warn }}", false +#if NET6_0_OR_GREATER + , UrlFormat = "{{ Url }}" +#endif +)] + {{ end }} {{ func render }} public static partial class {{ $0.Name | string.replace "-" "_" | string.replace " " "_" }} { {{~ for value in $0.Values ~}} - {{- summary value ~}} + {{- summary value -}} + {{~ if Warn ~}} + {{ obsolete }} + {{~ end }} {{~ if RawStrings ~}} public const string {{ value.Name | string.replace "-" "_" | string.replace " " "_" }} = """ diff --git a/src/ThisAssembly.Constants/ConstantsGenerator.cs b/src/ThisAssembly.Constants/ConstantsGenerator.cs index a8aa44ee..e5ff2f31 100644 --- a/src/ThisAssembly.Constants/ConstantsGenerator.cs +++ b/src/ThisAssembly.Constants/ConstantsGenerator.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Text; @@ -58,13 +58,24 @@ public void Initialize(IncrementalGeneratorInitializationContext context) .Select((c, t) => c.GlobalOptions.TryGetValue("build_property.ThisAssemblyNamespace", out var ns) && !string.IsNullOrEmpty(ns) ? ns : null) .Combine(context.ParseOptionsProvider); - context.RegisterSourceOutput( - files.Combine(right), - GenerateConstant); + var inputs = files.Combine(right); + // this is required to ensure status is registered properly independently of analyzer runs. + var sl = context.GetSponsorAdditionalFiles().Combine(context.AnalyzerConfigOptionsProvider); + context.RegisterSourceOutput(inputs.Combine(sl), + (spc, source) => + { + var (manifests, options) = source.Right; + var status = Diagnostics.GetOrSetStatus(manifests, options); + var warn = IsEditor && + (status == Devlooped.Sponsors.SponsorStatus.Unknown || status == Devlooped.Sponsors.SponsorStatus.Expired); + + GenerateConstant(spc, source.Left, warn ? string.Format( + CultureInfo.CurrentCulture, Resources.Editor_Disabled, Funding.Product, Funding.HelpUrl) : null); + }); } - void GenerateConstant(SourceProductionContext spc, ((string name, string value, string? comment, string root), (string? ns, ParseOptions parse)) args) + void GenerateConstant(SourceProductionContext spc, ((string name, string value, string? comment, string root), (string? ns, ParseOptions parse)) args, string? warn = default) { var ((name, value, comment, root), (ns, parse)) = args; var cs = (CSharpParseOptions)parse; @@ -83,7 +94,7 @@ void GenerateConstant(SourceProductionContext spc, ((string name, string value, // For now, we only support C# though var file = parse.Language.Replace("#", "Sharp") + ".sbntxt"; var template = Template.Parse(EmbeddedResource.GetContent(file), file); - var model = new Model(rootArea, ns); + var model = new Model(rootArea, ns, warn, Resources.Editor_DisabledRemarks, Funding.HelpUrl); if ((int)cs.LanguageVersion >= 1100) model.RawStrings = true; @@ -98,13 +109,6 @@ void GenerateConstant(SourceProductionContext spc, ((string name, string value, .GetText() .ToString(); } - //else if (language == LanguageNames.VisualBasic) - //{ - // output = Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory.ParseCompilationUnit(output) - // .NormalizeWhitespace() - // .GetText() - // .ToString(); - //} spc.AddSource($"{root}.{name}.g.cs", SourceText.From(output, Encoding.UTF8)); } diff --git a/src/ThisAssembly.Constants/Model.cs b/src/ThisAssembly.Constants/Model.cs index 8945f776..68ecf170 100644 --- a/src/ThisAssembly.Constants/Model.cs +++ b/src/ThisAssembly.Constants/Model.cs @@ -9,7 +9,7 @@ namespace ThisAssembly; [DebuggerDisplay("Values = {RootArea.Values.Count}")] -record Model(Area RootArea, string? Namespace) +record Model(Area RootArea, string? Namespace, string? Warn = default, string? WarnSummary = default, string Url = Devlooped.Sponsors.SponsorLink.Funding.HelpUrl) { public bool RawStrings { get; set; } = false; public string Version => Assembly.GetExecutingAssembly().GetName().Version.ToString(3); diff --git a/src/ThisAssembly.Tests/Tests.cs b/src/ThisAssembly.Tests/Tests.cs index b29f5a85..3b596946 100644 --- a/src/ThisAssembly.Tests/Tests.cs +++ b/src/ThisAssembly.Tests/Tests.cs @@ -1,8 +1,9 @@ -using System.Diagnostics.CodeAnalysis; +using System; +using System.Diagnostics.CodeAnalysis; using System.IO; -using Devlooped; using Xunit; using Xunit.Abstractions; +//using ThisAssembly = ThisAssemblyTests [assembly: SuppressMessage("SponsorLink", "SL04")] @@ -10,7 +11,6 @@ namespace ThisAssemblyTests; public record class Tests(ITestOutputHelper Output) { - DateTime dxt = DateTime.Now; [Fact] public void CanReadResourceFile() => Assert.NotNull(ResourceFile.Load("Resources.resx", "Strings")); diff --git a/src/ThisAssembly.Tests/ThisAssembly.Tests.csproj b/src/ThisAssembly.Tests/ThisAssembly.Tests.csproj index 6e72472b..0edd29cf 100644 --- a/src/ThisAssembly.Tests/ThisAssembly.Tests.csproj +++ b/src/ThisAssembly.Tests/ThisAssembly.Tests.csproj @@ -3,7 +3,7 @@ false net8.0 - Devlooped + ThisAssemblyTests A Description with a newline and @@ -17,10 +17,10 @@ net472 ThisAssemblyTests true - CS8981;$(NoWarn) + CS0618;CS8981;TA100;$(NoWarn) - + @@ -87,10 +87,18 @@ - true + + + + $(Version) + + + + +