diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/Constants/Strings.cs b/Analyzers/Terminal.Gui.Analyzers.Internal/Constants/Strings.cs new file mode 100644 index 000000000..e03d5fcc3 --- /dev/null +++ b/Analyzers/Terminal.Gui.Analyzers.Internal/Constants/Strings.cs @@ -0,0 +1,202 @@ +// ReSharper disable MemberCanBePrivate.Global + +using System; +using System.CodeDom.Compiler; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using Terminal.Gui.Analyzers.Internal.Attributes; + +namespace Terminal.Gui.Analyzers.Internal.Constants; + +/// String constants for frequently-used boilerplate. +/// These are for performance, instead of using Roslyn to build it all during execution of analyzers. +internal static class Strings +{ + internal const string AnalyzersAttributesNamespace = $"{InternalAnalyzersNamespace}.Attributes"; + + internal const string AssemblyExtendedEnumTypeAttributeFullName = $"{AnalyzersAttributesNamespace}.{nameof (AssemblyExtendedEnumTypeAttribute)}"; + + internal const string DefaultTypeNameSuffix = "Extensions"; + + internal const string FallbackClassNamespace = $"{TerminalGuiRootNamespace}"; + + internal const string InternalAnalyzersNamespace = $"{AnalyzersRootNamespace}.Internal"; + + internal const string TerminalGuiRootNamespace = "Terminal.Gui"; + + private const string AnalyzersRootNamespace = $"{TerminalGuiRootNamespace}.Analyzers"; + private const string NetStandard20CompatibilityNamespace = $"{InternalAnalyzersNamespace}.Compatibility"; + + /// + /// Names of dotnet namespaces and types. Included as compile-time constants to avoid unnecessary work for the Roslyn + /// source generators. + /// + /// Implemented as nested static types because XmlDoc doesn't work on namespaces. + internal static class DotnetNames + { + /// Fully-qualified attribute type names. Specific applications (uses) are in . + internal static class Attributes + { + /// + internal const string CompilerGenerated = $"{Namespaces.System_Runtime_CompilerServices}.{nameof (CompilerGeneratedAttribute)}"; + + /// + internal const string DebuggerNonUserCode = $"{Namespaces.System_Diagnostics}.{nameof (DebuggerNonUserCodeAttribute)}"; + + /// + internal const string ExcludeFromCodeCoverage = $"{Namespaces.System_Diagnostics_CodeAnalysis}.{nameof (ExcludeFromCodeCoverageAttribute)}"; + + internal const string Flags = $"{Namespaces.SystemNS}.{nameof (FlagsAttribute)}"; + + internal const string GeneratedCode = $"{Namespaces.System_CodeDom_Compiler}.{nameof (GeneratedCodeAttribute)}"; + + /// + /// Use of this attribute should be carefully evaluated. + internal const string MethodImpl = $"{Namespaces.System_Runtime_CompilerServices}.{nameof (MethodImplAttribute)}"; + + /// Attributes formatted for use in code, including square brackets. + internal static class Applications + { + // ReSharper disable MemberHidesStaticFromOuterClass + internal const string Flags = $"[{Attributes.Flags}]"; + + /// + internal const string GeneratedCode = $"""[{Attributes.GeneratedCode}("{InternalAnalyzersNamespace}","1.0")]"""; + + /// + /// Use of this attribute should be carefully evaluated. + internal const string AggressiveInlining = $"[{MethodImpl}({Types.MethodImplOptions}.{nameof (MethodImplOptions.AggressiveInlining)})]"; + + /// + internal const string DebuggerNonUserCode = $"[{Attributes.DebuggerNonUserCode}]"; + + /// + internal const string CompilerGenerated = $"[{Attributes.CompilerGenerated}]"; + + /// + internal const string ExcludeFromCodeCoverage = $"[{Attributes.ExcludeFromCodeCoverage}]"; + + // ReSharper restore MemberHidesStaticFromOuterClass + } + } + + /// Names of dotnet namespaces. + internal static class Namespaces + { + internal const string SystemNS = nameof (System); + internal const string System_CodeDom = $"{SystemNS}.{nameof (System.CodeDom)}"; + internal const string System_CodeDom_Compiler = $"{System_CodeDom}.{nameof (System.CodeDom.Compiler)}"; + internal const string System_ComponentModel = $"{SystemNS}.{nameof (System.ComponentModel)}"; + internal const string System_Diagnostics = $"{SystemNS}.{nameof (System.Diagnostics)}"; + internal const string System_Diagnostics_CodeAnalysis = $"{System_Diagnostics}.{nameof (System.Diagnostics.CodeAnalysis)}"; + internal const string System_Numerics = $"{SystemNS}.{nameof (System.Numerics)}"; + internal const string System_Runtime = $"{SystemNS}.{nameof (System.Runtime)}"; + internal const string System_Runtime_CompilerServices = $"{System_Runtime}.{nameof (System.Runtime.CompilerServices)}"; + } + + internal static class Types + { + internal const string Attribute = $"{Namespaces.SystemNS}.{nameof (System.Attribute)}"; + internal const string AttributeTargets = $"{Namespaces.SystemNS}.{nameof (System.AttributeTargets)}"; + internal const string AttributeUsageAttribute = $"{Namespaces.SystemNS}.{nameof (System.AttributeUsageAttribute)}"; + + internal const string MethodImplOptions = + $"{Namespaces.System_Runtime_CompilerServices}.{nameof (System.Runtime.CompilerServices.MethodImplOptions)}"; + } + } + + internal static class Templates + { + internal const string AutoGeneratedCommentBlock = $""" + //------------------------------------------------------------------------------ + // + // This file and the code it contains was generated by a source generator in + // the {InternalAnalyzersNamespace} library. + // + // Modifications to this file are not supported and will be lost when + // source generation is triggered, either implicitly or explicitly. + // + //------------------------------------------------------------------------------ + """; + + /// + /// A set of explicit type aliases to work around Terminal.Gui having name collisions with types like + /// . + /// + internal const string DotnetExplicitTypeAliasUsingDirectives = $""" + using Attribute = {DotnetNames.Types.Attribute}; + using AttributeUsageAttribute = {DotnetNames.Types.AttributeUsageAttribute}; + using GeneratedCode = {DotnetNames.Attributes.GeneratedCode}; + """; + + /// Using directives for common namespaces in generated code. + internal const string DotnetNamespaceUsingDirectives = $""" + using {DotnetNames.Namespaces.SystemNS}; + using {DotnetNames.Namespaces.System_CodeDom}; + using {DotnetNames.Namespaces.System_CodeDom_Compiler}; + using {DotnetNames.Namespaces.System_ComponentModel}; + using {DotnetNames.Namespaces.System_Numerics}; + using {DotnetNames.Namespaces.System_Runtime}; + using {DotnetNames.Namespaces.System_Runtime_CompilerServices}; + """; + + /// + /// A set of empty namespaces that MAY be referenced in generated code, especially in using statements, + /// which are always included to avoid additional complexity due to conditional compilation. + /// + internal const string DummyNamespaceDeclarations = $$""" + // These are dummy declarations to avoid complexity with conditional compilation. + #pragma warning disable IDE0079 // Remove unnecessary suppression + #pragma warning disable RCS1259 // Remove empty syntax + namespace {{TerminalGuiRootNamespace}} { } + namespace {{AnalyzersRootNamespace}} { } + namespace {{InternalAnalyzersNamespace}} { } + namespace {{NetStandard20CompatibilityNamespace}} { } + namespace {{AnalyzersAttributesNamespace}} { } + #pragma warning restore RCS1259 // Remove empty syntax + #pragma warning restore IDE0079 // Remove unnecessary suppression + """; + + internal const string StandardHeader = $""" + {AutoGeneratedCommentBlock} + // ReSharper disable RedundantUsingDirective + // ReSharper disable once RedundantNullableDirective + {NullableContextDirective} + + {StandardUsingDirectivesText} + """; + + /// + /// Standard set of using directives for generated extension method class files. + /// Not all are always needed, but all are included so we don't have to worry about it. + /// + internal const string StandardUsingDirectivesText = $""" + {DotnetNamespaceUsingDirectives} + {DotnetExplicitTypeAliasUsingDirectives} + using {TerminalGuiRootNamespace}; + using {AnalyzersRootNamespace}; + using {InternalAnalyzersNamespace}; + using {AnalyzersAttributesNamespace}; + using {NetStandard20CompatibilityNamespace}; + """; + + internal const string AttributesForGeneratedInterfaces = $""" + {DotnetNames.Attributes.Applications.GeneratedCode} + {DotnetNames.Attributes.Applications.CompilerGenerated} + """; + + internal const string AttributesForGeneratedTypes = $""" + {DotnetNames.Attributes.Applications.GeneratedCode} + {DotnetNames.Attributes.Applications.CompilerGenerated} + {DotnetNames.Attributes.Applications.DebuggerNonUserCode} + {DotnetNames.Attributes.Applications.ExcludeFromCodeCoverage} + """; + + /// + /// Preprocessor directive to enable nullability context for generated code.
+ /// This should always be emitted, as it applies only to generated code.
+ /// As such, generated code MUST be properly annotated. + ///
+ internal const string NullableContextDirective = "#nullable enable"; + } +}