diff --git a/src/Application.Interfaces/Filtering.cs b/src/Application.Interfaces/Filtering.cs index 1da149ac..c2864206 100644 --- a/src/Application.Interfaces/Filtering.cs +++ b/src/Application.Interfaces/Filtering.cs @@ -1,3 +1,5 @@ +using Common.Extensions; + namespace Application.Interfaces; /// @@ -13,7 +15,7 @@ public Filtering() public Filtering(string field) { - ArgumentException.ThrowIfNullOrEmpty(field); + field.ThrowIfNotValuedParameter(nameof(field)); if (!_fields.Contains(field)) { _fields.Add(field); diff --git a/src/Application.Interfaces/Sorting.cs b/src/Application.Interfaces/Sorting.cs index 03e37c04..36a7bfb0 100644 --- a/src/Application.Interfaces/Sorting.cs +++ b/src/Application.Interfaces/Sorting.cs @@ -1,3 +1,5 @@ +using Common.Extensions; + namespace Application.Interfaces; /// @@ -7,7 +9,7 @@ public class Sorting { public Sorting(string by, SortDirection direction = SortDirection.Ascending) { - ArgumentException.ThrowIfNullOrEmpty(by); + by.ThrowIfNotValuedParameter(nameof(by)); By = by; Direction = direction; } diff --git a/src/Common/Error.cs b/src/Common/Error.cs index 8ec9a4dc..37341145 100644 --- a/src/Common/Error.cs +++ b/src/Common/Error.cs @@ -1,4 +1,6 @@ +#if !ANALYZERS_NONPLATFORM using Common.Extensions; +#endif namespace Common; @@ -25,6 +27,7 @@ internal Error(ErrorCode code, string? message = null) public ErrorCode Code { get; } +#if !ANALYZERS_NONPLATFORM /// /// Wraps the existing message within the specified message /// @@ -39,7 +42,8 @@ public Error Wrap(string message) ? $"{message}{Environment.NewLine}\t{Message}" : message); } - +#endif + /// /// Creates a error /// diff --git a/src/Common/Extensions/CollectionExtensions.cs b/src/Common/Extensions/CollectionExtensions.cs index dc545b03..9e5679e2 100644 --- a/src/Common/Extensions/CollectionExtensions.cs +++ b/src/Common/Extensions/CollectionExtensions.cs @@ -1,5 +1,8 @@ -#if COMMON_PROJECT +#if COMMON_PROJECT || ANALYZERS_NONPLATFORM using System.Text; +#endif + +#if COMMON_PROJECT using JetBrains.Annotations; #endif @@ -11,7 +14,7 @@ namespace Common.Extensions; public static class CollectionExtensions { -#if COMMON_PROJECT || GENERATORS_WEB_API_PROJECT +#if COMMON_PROJECT || GENERATORS_WEB_API_PROJECT || ANALYZERS_NONPLATFORM /// /// Whether the string exists in the /// @@ -34,7 +37,7 @@ public static TResult First(this IReadOnlyList list) return list[0]; } #endif -#if COMMON_PROJECT || GENERATORS_WEB_API_PROJECT +#if COMMON_PROJECT || GENERATORS_WEB_API_PROJECT || ANALYZERS_NONPLATFORM /// /// Whether the collection contains any items /// @@ -44,7 +47,7 @@ public static bool HasAny(this IEnumerable? collection) { return false; } -#if COMMON_PROJECT +#if COMMON_PROJECT || ANALYZERS_NONPLATFORM return !collection.HasNone(); #elif GENERATORS_WEB_API_PROJECT return !collection!.HasNone(); @@ -59,7 +62,7 @@ public static bool HasNone(this IEnumerable collection) return !collection.Any(); } #endif -#if COMMON_PROJECT +#if COMMON_PROJECT || ANALYZERS_NONPLATFORM /// /// Joins all values separated by the /// @@ -78,7 +81,8 @@ public static string Join(this IEnumerable values, string separator) return stringBuilder.ToString(); } - +#endif +#if COMMON_PROJECT /// /// Returns a string value for all the items in the list, separated by the specified /// @@ -94,7 +98,8 @@ public static TResult Last(this IReadOnlyList list) { return list[^1]; } - +#endif +#if COMMON_PROJECT || ANALYZERS_NONPLATFORM /// /// Whether the string does not exist in the /// diff --git a/src/Common/Extensions/ObjectExtensions.cs b/src/Common/Extensions/ObjectExtensions.cs index e52ee6f8..3321208a 100644 --- a/src/Common/Extensions/ObjectExtensions.cs +++ b/src/Common/Extensions/ObjectExtensions.cs @@ -1,6 +1,8 @@ #if COMMON_PROJECT -using System.Diagnostics.CodeAnalysis; using AutoMapper; +#endif +#if COMMON_PROJECT || GENERATORS_WEB_API_PROJECT || ANALYZERS_NONPLATFORM || ANALYZERS_PLATFORM +using System.Diagnostics.CodeAnalysis; using JetBrains.Annotations; #endif @@ -20,7 +22,7 @@ public static TTarget Convert(this TSource source) return mapper.Map(source); } #endif -#if COMMON_PROJECT +#if COMMON_PROJECT || GENERATORS_WEB_API_PROJECT || ANALYZERS_NONPLATFORM || ANALYZERS_PLATFORM /// /// Whether the object does exist /// @@ -29,17 +31,8 @@ public static bool Exists([NotNullWhen(true)] this object? instance) { return instance is not null; } -#elif GENERATORS_WEB_API_PROJECT - /// - /// Whether the object does exist - /// - public static bool Exists(this object? instance) - { - return instance is not null; - } - #endif -#if COMMON_PROJECT +#if COMMON_PROJECT || ANALYZERS_NONPLATFORM /// /// Whether the parameter from being invalid according to the , /// and if invalid, returns a error @@ -93,7 +86,7 @@ public static bool IsNotValuedParameter(this string? value, string parameterName return IsInvalidParameter(value.HasValue, parameterName, null, out error); } #endif -#if COMMON_PROJECT +#if COMMON_PROJECT || GENERATORS_WEB_API_PROJECT || ANALYZERS_NONPLATFORM || ANALYZERS_PLATFORM /// /// Whether the object does not exist /// @@ -102,14 +95,6 @@ public static bool NotExists([NotNullWhen(false)] this object? instance) { return instance is null; } -#elif GENERATORS_WEB_API_PROJECT - /// - /// Whether the object does not exist - /// - public static bool NotExists(this object? instance) - { - return instance is null; - } #endif #if COMMON_PROJECT /// @@ -145,7 +130,8 @@ public static void ThrowIfInvalidParameter(this TValue? value, Predicate throw new ArgumentOutOfRangeException(parameterName, errorMessage); } } - +#endif +#if COMMON_PROJECT || ANALYZERS_NONPLATFORM /// /// Throws an if the specified does not have a value /// @@ -172,5 +158,17 @@ private static bool IsInvalidParameter(Func predicate, string parameterNam error = Error.NoError; return false; } + + /// + /// Throws an if the specified is null + /// + public static void ThrowIfNullParameter(this TValue? value, string parameterName, + string? errorMessage = null) + { + if (value is null) + { + throw new ArgumentNullException(parameterName, errorMessage); + } + } #endif -} +} \ No newline at end of file diff --git a/src/Common/Extensions/StringExtensions.cs b/src/Common/Extensions/StringExtensions.cs index ba36d420..e8424d08 100644 --- a/src/Common/Extensions/StringExtensions.cs +++ b/src/Common/Extensions/StringExtensions.cs @@ -1,18 +1,23 @@ #if COMMON_PROJECT -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; using System.Text.RegularExpressions; +#endif +#if COMMON_PROJECT || GENERATORS_WEB_API_PROJECT || GENERATORS_COMMON_PROJECT || ANALYZERS_NONPLATFORM +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using JetBrains.Annotations; +#endif -#elif GENERATORS_WEB_API_PROJECT +#if GENERATORS_WEB_API_PROJECT || ANALYZERS_NONPLATFORM using System.Runtime.Serialization; using System.Runtime.Serialization.Json; using System.Text; -#elif GENERATORS_COMMON_PROJECT +#endif + +#if GENERATORS_COMMON_PROJECT using System.Globalization; using System.Text; #endif @@ -24,7 +29,7 @@ namespace Common.Extensions; #endif public static class StringExtensions { -#if COMMON_PROJECT +#if COMMON_PROJECT || GENERATORS_WEB_API_PROJECT || ANALYZERS_NONPLATFORM /// /// Defines the casing used in JSON serialization /// @@ -33,10 +38,11 @@ public enum JsonCasing Pascal, Camel } - +#endif +#if COMMON_PROJECT private static readonly TimeSpan DefaultRegexTimeout = TimeSpan.FromSeconds(10); #endif -#if COMMON_PROJECT || GENERATORS_WEB_API_PROJECT +#if COMMON_PROJECT || GENERATORS_WEB_API_PROJECT || ANALYZERS_NONPLATFORM /// /// Whether the is the same as the value (case-insensitive) /// @@ -45,7 +51,7 @@ public static bool EqualsIgnoreCase(this string value, string other) return string.Equals(value, other, StringComparison.OrdinalIgnoreCase); } #endif -#if COMMON_PROJECT +#if COMMON_PROJECT || ANALYZERS_NONPLATFORM /// /// Whether the is precisely the same as the value (case-sensitive) /// @@ -53,7 +59,8 @@ public static bool EqualsOrdinal(this string value, string other) { return string.Equals(value, other, StringComparison.Ordinal); } - +#endif +#if COMMON_PROJECT || ANALYZERS_NONPLATFORM /// /// Formats the with the /// @@ -78,7 +85,7 @@ public static string Format(this string value, params object[] arguments) PropertyNameCaseInsensitive = true }); } -#elif GENERATORS_WEB_API_PROJECT +#elif GENERATORS_WEB_API_PROJECT || ANALYZERS_NONPLATFORM public static TObject FromJson(this string json) where TObject : new() { @@ -87,11 +94,27 @@ public static TObject FromJson(this string json) return new TObject(); } - var serializer = new DataContractJsonSerializer(typeof(TObject), new DataContractJsonSerializerSettings()); + var deserialized = FromJson(json, typeof(TObject)); + if (deserialized is not null) + { + return (TObject)deserialized; + } + + return new TObject(); + } + + public static object? FromJson(this string json, Type type) + { + if (json.HasNoValue()) + { + return null; + } + + var serializer = new DataContractJsonSerializer(type, new DataContractJsonSerializerSettings()); using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(json))) { - return (TObject)serializer.ReadObject(ms); + return serializer.ReadObject(ms); } } #endif @@ -112,7 +135,7 @@ public static TObject FromJson(this string json) }); } #endif -#if COMMON_PROJECT +#if COMMON_PROJECT || GENERATORS_WEB_API_PROJECT || GENERATORS_COMMON_PROJECT || ANALYZERS_NONPLATFORM /// /// Whether the string value contains no value: it is either: null, empty or only whitespaces /// @@ -132,22 +155,6 @@ public static bool HasValue([NotNullWhen(true)] this string? value) { return !string.IsNullOrEmpty(value) && !string.IsNullOrWhiteSpace(value); } -#elif GENERATORS_WEB_API_PROJECT || GENERATORS_COMMON_PROJECT - /// - /// Whether the string value contains no value: it is either: null, empty or only whitespaces - /// - public static bool HasNoValue(this string? value) - { - return string.IsNullOrEmpty(value) || string.IsNullOrWhiteSpace(value); - } - - /// - /// Whether the string value contains any value except: null, empty or only whitespaces - /// - public static bool HasValue(this string? value) - { - return !string.IsNullOrEmpty(value) && !string.IsNullOrWhiteSpace(value); - } #endif #if COMMON_PROJECT /// @@ -261,7 +268,7 @@ public static string ToCamelCase(this string value) return char.ToLowerInvariant(titleCase[0]) + titleCase.Substring(1); } #endif -#if COMMON_PROJECT +#if COMMON_PROJECT || ANALYZERS_NONPLATFORM /// /// Converts the to a integer value /// @@ -321,8 +328,9 @@ public static int ToIntOrDefault(this string? value, int defaultValue) : JsonIgnoreCondition.WhenWritingNull }); } -#elif GENERATORS_WEB_API_PROJECT - public static string? ToJson(this TObject? value, bool? prettyPrint = false) +#elif GENERATORS_WEB_API_PROJECT || ANALYZERS_NONPLATFORM || ANALYZERS_NONPLATFORM + public static string? ToJson(this TObject? value, bool? prettyPrint = true, JsonCasing casing = + JsonCasing.Pascal) { if (value is null) { diff --git a/src/Common/Optional.cs b/src/Common/Optional.cs index c2ec687e..e83e6df6 100644 --- a/src/Common/Optional.cs +++ b/src/Common/Optional.cs @@ -65,7 +65,7 @@ public static Optional None() /// public static Optional Some(TValue value) { - ArgumentNullException.ThrowIfNull(value); + value.ThrowIfNullParameter(nameof(value)); if (value.TryGetContainedValue(out var contained)) { diff --git a/src/Directory.Build.props b/src/Directory.Build.props index d336ae00..3743c843 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -9,11 +9,6 @@ false - - - HOSTEDONAZURE - - $([System.IO.File]::ReadAllText('$(MSBuildProjectDirectory)\..\GlobalAssemblyInfo.cs')) @@ -80,7 +75,9 @@ AnyCPU Debug AnyCPU + HOSTEDONAZURE + true full diff --git a/src/Infrastructure.Common/Infrastructure.Common.csproj b/src/Infrastructure.Common/Infrastructure.Common.csproj index d3795bf4..e518f6f6 100644 --- a/src/Infrastructure.Common/Infrastructure.Common.csproj +++ b/src/Infrastructure.Common/Infrastructure.Common.csproj @@ -11,6 +11,7 @@ + @@ -19,6 +20,7 @@ + diff --git a/src/Infrastructure.Web.Api.Interfaces/AuthorizeAttribute.cs b/src/Infrastructure.Web.Api.Interfaces/AuthorizeAttribute.cs index 4e9213bf..1d77cda8 100644 --- a/src/Infrastructure.Web.Api.Interfaces/AuthorizeAttribute.cs +++ b/src/Infrastructure.Web.Api.Interfaces/AuthorizeAttribute.cs @@ -3,7 +3,7 @@ using Common.Extensions; using Domain.Interfaces.Authorization; using Infrastructure.Interfaces; -#if GENERATORS_WEB_API_PROJECT +#if GENERATORS_WEB_API_PROJECT || ANALYZERS_NONPLATFORM using System.Runtime.Serialization; #endif @@ -346,17 +346,17 @@ private static FeatureLevel[] ToTenant(Features features) /// /// Provides a serializable class for storing policy names /// -#if GENERATORS_WEB_API_PROJECT +#if GENERATORS_WEB_API_PROJECT || ANALYZERS_NONPLATFORM [DataContract] #endif public class PolicyName { -#if GENERATORS_WEB_API_PROJECT +#if GENERATORS_WEB_API_PROJECT || ANALYZERS_NONPLATFORM [DataMember(Order = 1, EmitDefaultValue = false)] #endif public PolicyNameStage? Features { get; set; } -#if GENERATORS_WEB_API_PROJECT +#if GENERATORS_WEB_API_PROJECT || ANALYZERS_NONPLATFORM [DataMember(Order = 2, EmitDefaultValue = false)] #endif public PolicyNameStage? Roles { get; set; } @@ -365,17 +365,17 @@ public class PolicyName /// /// Provides a serializable class for storing policy stages /// -#if GENERATORS_WEB_API_PROJECT +#if GENERATORS_WEB_API_PROJECT || ANALYZERS_NONPLATFORM [DataContract] #endif public class PolicyNameStage { -#if GENERATORS_WEB_API_PROJECT +#if GENERATORS_WEB_API_PROJECT || ANALYZERS_NONPLATFORM [DataMember(Order = 1, EmitDefaultValue = false)] #endif public List? Tenant { get; set; } -#if GENERATORS_WEB_API_PROJECT +#if GENERATORS_WEB_API_PROJECT || ANALYZERS_NONPLATFORM [DataMember(Order = 1, EmitDefaultValue = false)] #endif public List? Platform { get; set; } diff --git a/src/SaaStack.sln b/src/SaaStack.sln index a4848427..bf34687b 100644 --- a/src/SaaStack.sln +++ b/src/SaaStack.sln @@ -320,6 +320,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrganizationsInfrastructure EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrganizationsInfrastructure.UnitTests", "OrganizationsInfrastructure.UnitTests\OrganizationsInfrastructure.UnitTests.csproj", "{B2ABB588-A7D4-44DB-8A2B-C1657D57D546}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTesting.CodeAnalysis.Common", "UnitTesting.CodeAnalysis.Common\UnitTesting.CodeAnalysis.Common.csproj", "{3A491D02-702A-4738-B3F5-26066E60F834}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1011,6 +1013,12 @@ Global {B2ABB588-A7D4-44DB-8A2B-C1657D57D546}.Release|Any CPU.Build.0 = Release|Any CPU {B2ABB588-A7D4-44DB-8A2B-C1657D57D546}.ReleaseForDeploy|Any CPU.ActiveCfg = ReleaseForDeploy|Any CPU {B2ABB588-A7D4-44DB-8A2B-C1657D57D546}.ReleaseForDeploy|Any CPU.Build.0 = ReleaseForDeploy|Any CPU + {3A491D02-702A-4738-B3F5-26066E60F834}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3A491D02-702A-4738-B3F5-26066E60F834}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3A491D02-702A-4738-B3F5-26066E60F834}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3A491D02-702A-4738-B3F5-26066E60F834}.Release|Any CPU.Build.0 = Release|Any CPU + {3A491D02-702A-4738-B3F5-26066E60F834}.ReleaseForDeploy|Any CPU.ActiveCfg = ReleaseForDeploy|Any CPU + {3A491D02-702A-4738-B3F5-26066E60F834}.ReleaseForDeploy|Any CPU.Build.0 = ReleaseForDeploy|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {F5C77A86-38AF-40E4-82FC-617E624B2754} = {508E7DA4-4DF2-4201-955D-CCF70C41AD05} @@ -1165,5 +1173,6 @@ Global {4DBA0B71-413D-43A9-AF68-150135A74F5B} = {90ED1D1C-5960-4F56-94F1-8063490725C4} {B2ABB588-A7D4-44DB-8A2B-C1657D57D546} = {90ED1D1C-5960-4F56-94F1-8063490725C4} {EA58877D-3023-429C-A1A8-E8479441139E} = {D3B68FF7-293B-4458-B8D8-49D3DF59B495} + {3A491D02-702A-4738-B3F5-26066E60F834} = {5838EE94-374F-4A6F-A231-1BC1C87985F4} EndGlobalSection EndGlobal diff --git a/src/Tools.Analyzers.Common/Tools.Analyzers.Common.csproj b/src/Tools.Analyzers.Common/Tools.Analyzers.Common.csproj index 32f4cae6..f32aead7 100644 --- a/src/Tools.Analyzers.Common/Tools.Analyzers.Common.csproj +++ b/src/Tools.Analyzers.Common/Tools.Analyzers.Common.csproj @@ -1,7 +1,9 @@ - net8.0 + netstandard2.0 + latest + enable true true diff --git a/src/Tools.Analyzers.NonPlatform.UnitTests/DomainDrivenDesignAnalyzerSpec.cs b/src/Tools.Analyzers.NonPlatform.UnitTests/DomainDrivenDesignAnalyzerSpec.cs index 4d72fbac..fa1f3e81 100644 --- a/src/Tools.Analyzers.NonPlatform.UnitTests/DomainDrivenDesignAnalyzerSpec.cs +++ b/src/Tools.Analyzers.NonPlatform.UnitTests/DomainDrivenDesignAnalyzerSpec.cs @@ -1,8 +1,8 @@ extern alias NonPlatformAnalyzers; -using JetBrains.Annotations; using Xunit; using NonPlatform_DomainDrivenDesignAnalyzer = NonPlatformAnalyzers::Tools.Analyzers.NonPlatform.DomainDrivenDesignAnalyzer; +using UsedImplicitly = NonPlatformAnalyzers::JetBrains.Annotations.UsedImplicitlyAttribute; namespace Tools.Analyzers.NonPlatform.UnitTests; diff --git a/src/Tools.Analyzers.NonPlatform.UnitTests/DomainDrivenDesignCodeFixSpec.cs b/src/Tools.Analyzers.NonPlatform.UnitTests/DomainDrivenDesignCodeFixSpec.cs index 572e49b7..1b32d8cd 100644 --- a/src/Tools.Analyzers.NonPlatform.UnitTests/DomainDrivenDesignCodeFixSpec.cs +++ b/src/Tools.Analyzers.NonPlatform.UnitTests/DomainDrivenDesignCodeFixSpec.cs @@ -1,10 +1,10 @@ extern alias NonPlatformAnalyzers; -using JetBrains.Annotations; using Xunit; using NonPlatform_DomainDrivenDesignAnalyzer = NonPlatformAnalyzers::Tools.Analyzers.NonPlatform.DomainDrivenDesignAnalyzer; using NonPlatform_DomainDrivenDesignCodeFix = NonPlatformAnalyzers::Tools.Analyzers.NonPlatform.DomainDrivenDesignCodeFix; +using UsedImplicitly = NonPlatformAnalyzers::JetBrains.Annotations.UsedImplicitlyAttribute; namespace Tools.Analyzers.NonPlatform.UnitTests; diff --git a/src/Tools.Analyzers.NonPlatform.UnitTests/Tools.Analyzers.NonPlatform.UnitTests.csproj b/src/Tools.Analyzers.NonPlatform.UnitTests/Tools.Analyzers.NonPlatform.UnitTests.csproj index 61c1f69e..18cbaf58 100644 --- a/src/Tools.Analyzers.NonPlatform.UnitTests/Tools.Analyzers.NonPlatform.UnitTests.csproj +++ b/src/Tools.Analyzers.NonPlatform.UnitTests/Tools.Analyzers.NonPlatform.UnitTests.csproj @@ -6,17 +6,12 @@ - - + - - - - diff --git a/src/Tools.Analyzers.NonPlatform.UnitTests/Verify.cs b/src/Tools.Analyzers.NonPlatform.UnitTests/Verify.cs index b0010131..916b2929 100644 --- a/src/Tools.Analyzers.NonPlatform.UnitTests/Verify.cs +++ b/src/Tools.Analyzers.NonPlatform.UnitTests/Verify.cs @@ -1,21 +1,16 @@ extern alias CommonAnalyzers; +extern alias NonPlatformAnalyzers; using System.Reflection; -using Common; -using Common.Extensions; -using Domain.Common; -using Domain.Interfaces; -using Infrastructure.Web.Api.Common; -using Infrastructure.Web.Api.Interfaces; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp.Testing; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Testing; +using NonPlatformAnalyzers::QueryAny; using NuGet.Frameworks; -using QueryAny; using AnalyzerConstants = CommonAnalyzers::Tools.Analyzers.Common.AnalyzerConstants; using Task = System.Threading.Tasks.Task; - +using ObjectExtensions = NonPlatformAnalyzers::Common.Extensions.ObjectExtensions; namespace Tools.Analyzers.NonPlatform.UnitTests; public static class Verify @@ -27,12 +22,7 @@ public static class Verify { typeof(Verify).Assembly, typeof(AnalyzerConstants).Assembly, - typeof(Query).Assembly, - typeof(CommonMarker).Assembly, - typeof(DomainInterfacesMarker).Assembly, - typeof(DomainCommonMarker).Assembly, - typeof(InfrastructureWebApiInterfacesMarker).Assembly, - typeof(InfrastructureWebApiCommonMarker).Assembly + typeof(IQueryableEntity).Assembly, }; // HACK: we have to define the .NET 8.0 framework here, @@ -125,7 +115,7 @@ private static async Task DiagnosticExists(DiagnosticDescriptor descr (int locationX, int locationY, string argument) expected1, params object?[]? messageArgs) where TAnalyzer : DiagnosticAnalyzer, new() { - var arguments = messageArgs.Exists() && messageArgs.Any() + var arguments = ObjectExtensions.Exists(messageArgs) && messageArgs.Any() ? new object[] { expected1.argument }.Concat(messageArgs) : new object[] { expected1.argument }; diff --git a/src/Tools.Analyzers.NonPlatform.UnitTests/WebApiClassAnalyzerSpec.cs b/src/Tools.Analyzers.NonPlatform.UnitTests/WebApiClassAnalyzerSpec.cs index 7ea32a7e..7feb327b 100644 --- a/src/Tools.Analyzers.NonPlatform.UnitTests/WebApiClassAnalyzerSpec.cs +++ b/src/Tools.Analyzers.NonPlatform.UnitTests/WebApiClassAnalyzerSpec.cs @@ -1,10 +1,16 @@ extern alias NonPlatformAnalyzers; -using Application.Interfaces; -using Infrastructure.Web.Api.Interfaces; -using JetBrains.Annotations; using Xunit; using TypeExtensions = NonPlatformAnalyzers::Tools.Analyzers.NonPlatform.TypeExtensions; using WebApiClassAnalyzer = NonPlatformAnalyzers::Tools.Analyzers.NonPlatform.WebApiClassAnalyzer; +using ServiceOperation = NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.ServiceOperation; +using IWebResponse = NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.IWebResponse; +using IWebSearchResponse = NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.IWebSearchResponse; +using Route = NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.RouteAttribute; +using Authorize = NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.AuthorizeAttribute; +using SearchResultMetadata = NonPlatformAnalyzers::Application.Interfaces.SearchResultMetadata; +using AccessType = NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.AccessType; +using Roles = NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.Roles; +using UsedImplicitly = NonPlatformAnalyzers::JetBrains.Annotations.UsedImplicitlyAttribute; namespace Tools.Analyzers.NonPlatform.UnitTests; @@ -1628,43 +1634,43 @@ public class TestSearchResponse : IWebSearchResponse } [UsedImplicitly] -public class TestNoRouteAttributeRequest : IWebRequest; +public class TestNoRouteAttributeRequest : NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.IWebRequest; [Route("/aresource", ServiceOperation.Search)] [UsedImplicitly] -public class TestSearchRouteAttributeRequest : IWebRequest; +public class TestSearchRouteAttributeRequest : NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.IWebRequest; [Route("/aresource", ServiceOperation.Post)] [UsedImplicitly] -public class TestPostRouteAttributeRequest : IWebRequest; +public class TestPostRouteAttributeRequest : NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.IWebRequest; [Route("/aresource", ServiceOperation.Get)] [UsedImplicitly] -public class TestGetRouteAttributeRequest : IWebRequest; +public class TestGetRouteAttributeRequest : NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.IWebRequest; [Route("/aresource/1", ServiceOperation.Get)] [UsedImplicitly] -public class TestGetRouteAttributeRequest1 : IWebRequest; +public class TestGetRouteAttributeRequest1 : NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.IWebRequest; [Route("/aresource/2", ServiceOperation.Get)] [UsedImplicitly] -public class TestGetRouteAttributeRequest2 : IWebRequest; +public class TestGetRouteAttributeRequest2 : NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.IWebRequest; [Route("/aresource/3", ServiceOperation.Get)] [UsedImplicitly] -public class TestGetRouteAttributeRequest3 : IWebRequest; +public class TestGetRouteAttributeRequest3 : NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.IWebRequest; [Route("/anotherresource/1", ServiceOperation.Get)] [UsedImplicitly] -public class TestGetRouteAttributeRequest4 : IWebRequest; +public class TestGetRouteAttributeRequest4 : NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.IWebRequest; [Route("/aresource", ServiceOperation.PutPatch)] [UsedImplicitly] -public class TestPutPatchRouteAttributeRequest : IWebRequest; +public class TestPutPatchRouteAttributeRequest : NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.IWebRequest; [Route("/aresource", ServiceOperation.Delete)] [UsedImplicitly] -public class TestDeleteRouteAttributeRequest : IWebRequest; +public class TestDeleteRouteAttributeRequest : NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.IWebRequest; [AttributeUsage(AttributeTargets.Method)] [UsedImplicitly] @@ -1672,18 +1678,18 @@ public class TestAttribute : Attribute; [Route("/aresource", ServiceOperation.Post)] [UsedImplicitly] -public class TestAnonymousRouteNoAuthorizeAttributeRequest : IWebRequest; +public class TestAnonymousRouteNoAuthorizeAttributeRequest : NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.IWebRequest; [Route("/aresource", ServiceOperation.Post)] [Authorize(Roles.Platform_Standard)] [UsedImplicitly] -public class TestAnonymousRouteAuthorizeAttributeRequest : IWebRequest; +public class TestAnonymousRouteAuthorizeAttributeRequest : NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.IWebRequest; [Route("/aresource", ServiceOperation.Post, AccessType.Token)] [Authorize(Roles.Platform_Standard)] [UsedImplicitly] -public class TestSecureRouteAuthorizeAttributeRequest : IWebRequest; +public class TestSecureRouteAuthorizeAttributeRequest : NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.IWebRequest; [Route("/aresource", ServiceOperation.Post, AccessType.Token)] [UsedImplicitly] -public class TestSecureRouteNoAuthorizeAttributeRequest : IWebRequest; \ No newline at end of file +public class TestSecureRouteNoAuthorizeAttributeRequest : NonPlatformAnalyzers::Infrastructure.Web.Api.Interfaces.IWebRequest; \ No newline at end of file diff --git a/src/Tools.Analyzers.NonPlatform/Extensions/DictionaryExtensions.cs b/src/Tools.Analyzers.NonPlatform/Extensions/DictionaryExtensions.cs new file mode 100644 index 00000000..43eeacee --- /dev/null +++ b/src/Tools.Analyzers.NonPlatform/Extensions/DictionaryExtensions.cs @@ -0,0 +1,21 @@ +// ReSharper disable once CheckNamespace + +namespace Common.Extensions; + +public static class DictionaryExtensions2 +{ + /// + /// Adds the item to the dictionary if the key does not exist + /// + public static bool TryAdd(this IDictionary values, TKey key, TValue value) + { + if (values.ContainsKey(key)) + { + return false; + } + + values.Add(key, value); + + return true; + } +} \ No newline at end of file diff --git a/src/Tools.Analyzers.NonPlatform/Extensions/StringBuilderExtensions.cs b/src/Tools.Analyzers.NonPlatform/Extensions/StringBuilderExtensions.cs new file mode 100644 index 00000000..e9b03836 --- /dev/null +++ b/src/Tools.Analyzers.NonPlatform/Extensions/StringBuilderExtensions.cs @@ -0,0 +1,11 @@ +using System.Text; + +namespace Tools.Analyzers.NonPlatform.Extensions; + +public static class StringBuilderExtensions +{ + public static void AppendJoin(this StringBuilder builder, string separator, IEnumerable values) + { + builder.Append(string.Join(separator, values)); + } +} \ No newline at end of file diff --git a/src/Tools.Analyzers.NonPlatform/README.md b/src/Tools.Analyzers.NonPlatform/README.md index 428c2037..2fe1fe13 100644 --- a/src/Tools.Analyzers.NonPlatform/README.md +++ b/src/Tools.Analyzers.NonPlatform/README.md @@ -6,9 +6,12 @@ The individual analyzers will filter the individual projects their analyzers app # Development Workarounds +Roslyn Analyzers have to be built in NETSTANDARD2.0 for them to run in Visual Studio, but this is not the case to run in JetBrains Rider. +> This constraint exists to support analyzers working in older versions of the .NET Framework, and will exist until Microsoft fix the issue Visual Studio. This is another reason to use JetBrains Rider as the preferred IDE for working with this codebase. + C# Analyzers have difficulties running in the IDE if the code used in them has dependencies on other projects in the solution (and other nugets). -For example, referencing: `Tools.Analyzers.Common.csproj` +For example, referencing: `Common.csproj` This is especially problematic when those referenced projects have transient dependencies to types in AspNet (e.g., any project that has this reference: ``. diff --git a/src/Tools.Analyzers.NonPlatform/Reference/QueryAny.cs b/src/Tools.Analyzers.NonPlatform/Reference/QueryAny.cs new file mode 100644 index 00000000..da9f33d8 --- /dev/null +++ b/src/Tools.Analyzers.NonPlatform/Reference/QueryAny.cs @@ -0,0 +1,18 @@ +using JetBrains.Annotations; + +// ReSharper disable once CheckNamespace +namespace QueryAny; + +/// +/// HACK: This is a workaround to include types from the QueryAny library, since it cannot be used in netstandard20 +/// +[AttributeUsage(AttributeTargets.Class, Inherited = false)] +[UsedImplicitly] +public class EntityNameAttribute : Attribute +{ + public EntityNameAttribute(string name) + { + } +} + +public interface IQueryableEntity; \ No newline at end of file diff --git a/src/Tools.Analyzers.NonPlatform/Reference/System.Diagnostics.CodeAnalysis.cs b/src/Tools.Analyzers.NonPlatform/Reference/System.Diagnostics.CodeAnalysis.cs new file mode 100644 index 00000000..aeb26de7 --- /dev/null +++ b/src/Tools.Analyzers.NonPlatform/Reference/System.Diagnostics.CodeAnalysis.cs @@ -0,0 +1,30 @@ +#define INTERNAL_NULLABLE_ATTRIBUTES + +// ReSharper disable once CheckNamespace +namespace System.Diagnostics.CodeAnalysis; + +/// +/// HACK: This code is to enable the use of the '[NotNullWhen]' attribute that is not present in netstandard20 +/// Specifies that when a method returns , the parameter will not be null even if the +/// corresponding type allows it. +/// +[AttributeUsage(AttributeTargets.Parameter)] +#if INTERNAL_NULLABLE_ATTRIBUTES +internal +#else + public +#endif + sealed class NotNullWhenAttribute : Attribute +{ + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) + { + ReturnValue = returnValue; + } + + /// Gets the return value condition. + public bool ReturnValue { get; } +} \ No newline at end of file diff --git a/src/Tools.Analyzers.NonPlatform/Reference/System.Runtime.CompilerServices.cs b/src/Tools.Analyzers.NonPlatform/Reference/System.Runtime.CompilerServices.cs new file mode 100644 index 00000000..806512c9 --- /dev/null +++ b/src/Tools.Analyzers.NonPlatform/Reference/System.Runtime.CompilerServices.cs @@ -0,0 +1,48 @@ +using System.ComponentModel; + +// ReSharper disable once CheckNamespace +namespace System.Runtime.CompilerServices +{ +#if !NET5_0_OR_GREATER + + [EditorBrowsable(EditorBrowsableState.Never)] + internal static class IsExternalInit; + +#endif // !NET5_0_OR_GREATER + +#if !NET7_0_OR_GREATER + + /// + /// HACK: This code is to enable the use of the 'required' keyword that is not present in netstandard20 + /// + [AttributeUsage( + AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property, + Inherited = false)] + internal sealed class RequiredMemberAttribute : Attribute; + + [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] + internal sealed class CompilerFeatureRequiredAttribute : Attribute + { + public CompilerFeatureRequiredAttribute(string featureName) + { + FeatureName = featureName; + } + + public string FeatureName { get; } + + public bool IsOptional { get; init; } + + public const string RefStructs = nameof(RefStructs); + public const string RequiredMembers = nameof(RequiredMembers); + } + +#endif // !NET7_0_OR_GREATER +} + +namespace System.Diagnostics.CodeAnalysis +{ +#if !NET7_0_OR_GREATER + [AttributeUsage(AttributeTargets.Constructor)] + internal sealed class SetsRequiredMembersAttribute : Attribute; +#endif +} \ No newline at end of file diff --git a/src/Tools.Analyzers.NonPlatform/Tools.Analyzers.NonPlatform.csproj b/src/Tools.Analyzers.NonPlatform/Tools.Analyzers.NonPlatform.csproj index 9b3d1f95..f1c97a31 100644 --- a/src/Tools.Analyzers.NonPlatform/Tools.Analyzers.NonPlatform.csproj +++ b/src/Tools.Analyzers.NonPlatform/Tools.Analyzers.NonPlatform.csproj @@ -1,33 +1,30 @@ - net8.0 + netstandard2.0 + $(DefineConstants);ANALYZERS_NONPLATFORM + latest + enable true true true - $(NoWarn),RS2007;NU5128 + $(NoWarn),RS2007,NU5128 - - - - - - all runtime; build; native; contentfiles; analyzers; buildtransitive - + @@ -37,6 +34,249 @@ + + + Reference\Common\Annotations.cs + + + Reference\Common\Extensions\StringExtensions.cs + + + Reference\Common\Extensions\CollectionExtensions.cs + + + Reference\Common\Extensions\DictionaryExtensions.cs + + + Reference\Common\Extensions\ObjectExtensions.cs + + + Reference\Common\Error.cs + + + Reference\Common\Result.cs + + + Reference\Common\Optional.cs + + + Reference\Common\IRecorder.cs + + + Reference\Common\Resources.Designer.cs + + + Reference\Common\ICallContext.cs + + + Reference\Common\Recording\CrashLevel.cs + + + Reference\Infrastructure.Web.Api.Interfaces\ApiResult.cs + + + Reference\Infrastructure.Web.Api.Interfaces\IWebApiService.cs + + + Reference\Infrastructure.Web.Api.Interfaces\IWebRequest.cs + + + Reference\Infrastructure.Web.Api.Interfaces\IWebResponse.cs + + + Reference\Infrastructure.Web.Api.Interfaces\IWebSearchResponse.cs + + + Reference\Infrastructure.Web.Api.Interfaces\EmptyResponse.cs + + + Reference\Infrastructure.Web.Api.Interfaces\ServiceOperation.cs + + + Reference\Infrastructure.Web.Api.Interfaces\AuthorizeAttribute.cs + + + Reference\Infrastructure.Web.Api.Interfaces\AuthorizeAttribute.g.cs + + + Reference\Infrastructure.Web.Api.Interfaces\RouteAttribute.cs + + + Reference\Infrastructure.Interfaces\AuthenticationConstants.cs + + + Reference\Application.Interfaces\SearchResultMetadata.cs + + + Reference\Application.Interfaces\Filtering.cs + + + Reference\Application.Interfaces\Sorting.cs + + + Reference\Application.Interfaces\ICallerContext.cs + + + Reference\Application.Interfaces\ICallerContext.RolesAndFeatures.cs + + + Reference\Domain.Interfaces\Authorization\IHierarchicalLevel.cs + + + Reference\Domain.Interfaces\Authorization\HierarchicalLevelBase.cs + + + Reference\Domain.Interfaces\Authorization\FeatureLevel.cs + + + Reference\Domain.Interfaces\Authorization\RoleLevel.cs + + + Reference\Domain.Interfaces\Authorization\PlatformRoles.cs + + + Reference\Domain.Interfaces\Authorization\TenantRoles.cs + + + Reference\Domain.Interfaces\Authorization\PlatformFeatures.cs + + + Reference\Domain.Interfaces\Authorization\TenantFeatures.cs + + + Reference\Domain.Interfaces\Entities\IDehydratableEntity.cs + + + Reference\Domain.Interfaces\Entities\IAggregateRoot.cs + + + Reference\Domain.Interfaces\Entities\IEntity.cs + + + Reference\Domain.Interfaces\Entities\IDomainEvent.cs + + + Reference\Domain.Interfaces\Entities\IDomainEventProducingEntity.cs + + + Reference\Domain.Interfaces\Entities\IEventingEntity.cs + + + Reference\Domain.Interfaces\Entities\IIdentifiableEntity.cs + + + Reference\Domain.Interfaces\Entities\IDomainEventConsumingEntity.cs + + + Reference\Domain.Interfaces\Entities\IDehydratableAggregateRoot.cs + + + Reference\Domain.Interfaces\Entities\ITombstoneEvent.cs + + + Reference\Domain.Interfaces\Entities\IEventingAggregateRoot.cs + + + Reference\Domain.Interfaces\Entities\EventSourcedChangeEvent.cs + + + Reference\Domain.Interfaces\Entities\IChangeEventConsumingAggregateRoot.cs + + + Reference\Domain.Interfaces\Entities\IEventSourcedChangeEventMigrator.cs + + + Reference\Domain.Interfaces\Entities\IChangeEventProducingAggregateRoot.cs + + + Reference\Domain.Interfaces\ValueObjects\IValueObject.cs + + + Reference\Domain.Interfaces\ValueObjects\ISingleValueObject.cs + + + Reference\Domain.Interfaces\ValueObjects\SkipImmutabilityCheckAttribute.cs + + + Reference\Domain.Interfaces\ValueObjects\IDehydratableValueObject.cs + + + Reference\Domain.Interfaces\Services\IDependencyContainer.cs + + + Reference\Domain.Interfaces\IRehydratableObject.cs + + + Reference\Domain.Interfaces\HydrationProperties.cs + + + Reference\Domain.Interfaces\DomainFactories.cs + + + Reference\Domain.Common\Resources.Designer.cs + + + Reference\Domain.Common\Events\Global.cs + + + Reference\Domain.Common\Identity\IIdentifierFactory.cs + + + Reference\Domain.Common\Identity\FixedIdentifierFactory.cs + + + Reference\Domain.Common\Entities\EntityBase.cs + + + Reference\Domain.Common\Entities\AggregateRootBase.cs + + + Reference\Domain.Common\Entities\EventSourcedChangeEventExtensions.cs + + + Reference\Domain.Common\Extensions\HydrationPropertiesExtensions.cs + + + Reference\Domain.Common\Extensions\DomainEventExtensions.cs + + + Reference\Domain.Common\ValueObjects\Identifier.cs + + + Reference\Domain.Common\ValueObjects\EventStream.cs + + + Reference\Domain.Common\ValueObjects\IdentifierExtensions.cs + + + Reference\Domain.Common\ValueObjects\ValueObjectBase.cs + + + Reference\Domain.Common\ValueObjects\ValueObjectBase.Comparable.cs + + + Reference\Domain.Common\ValueObjects\ValueObjectBase.Equality.cs + + + Reference\Domain.Common\ValueObjects\SingleValueObjectBase.cs + + + Reference\Domain.Common\ValueObjects\SingleValueObjectBase.Equality.cs + + + Reference\Domain.Common\ValueObjects\SingleValueObjectBase.Comparable.cs + + + Reference\Domain.Common\ValueObjects\ValueObjectExtensions.cs + + + Reference\Domain.Common\ValueObjects\EventMetadata.cs + + + Reference\Domain.Common\ValueObjects\EventMetadataExtensions.cs + + + ResXFileCodeGenerator @@ -52,26 +292,43 @@ - + $(GetTargetPathDependsOn);GetDependencyTargetPaths + <_TargetFramework>8.0.2 + <_AspNetFrameworkInstallFolder>C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\$(_TargetFramework) + <_FrameworkInstallFolder>C:\Program Files\dotnet\shared\Microsoft.NETCore.App\$(_TargetFramework) - + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/src/Tools.Analyzers.NonPlatform/WebApiClassAnalyzer.cs b/src/Tools.Analyzers.NonPlatform/WebApiClassAnalyzer.cs index 25f2e9c9..44de51b7 100644 --- a/src/Tools.Analyzers.NonPlatform/WebApiClassAnalyzer.cs +++ b/src/Tools.Analyzers.NonPlatform/WebApiClassAnalyzer.cs @@ -428,7 +428,7 @@ public void SetRouteSegments(string? routePath) { if (routePath.HasValue()) { - RouteSegments = routePath.Split("/", StringSplitOptions.RemoveEmptyEntries); + RouteSegments = routePath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); } } } diff --git a/src/Tools.Analyzers.Platform.UnitTests/MissingDocsAnalyzerSpec.cs b/src/Tools.Analyzers.Platform.UnitTests/MissingDocsAnalyzerSpec.cs index 07af2227..6647f82a 100644 --- a/src/Tools.Analyzers.Platform.UnitTests/MissingDocsAnalyzerSpec.cs +++ b/src/Tools.Analyzers.Platform.UnitTests/MissingDocsAnalyzerSpec.cs @@ -1,7 +1,7 @@ extern alias PlatformAnalyzers; -using JetBrains.Annotations; using Xunit; -using Platform_MissingDocsAnalyzer = PlatformAnalyzers::Tools.Analyzers.Platform.MissingDocsAnalyzer; +using MissingDocsAnalyzer = PlatformAnalyzers::Tools.Analyzers.Platform.MissingDocsAnalyzer; +using UsedImplicitly = PlatformAnalyzers::JetBrains.Annotations.UsedImplicitlyAttribute; namespace Tools.Analyzers.Platform.UnitTests; @@ -20,7 +20,7 @@ public class AClass { }"; - await Verify.NoDiagnosticExists(input); + await Verify.NoDiagnosticExists(input); } [Fact] @@ -32,7 +32,7 @@ public class AClass { }"; - await Verify.NoDiagnosticExists(input); + await Verify.NoDiagnosticExists(input); } [Fact] @@ -40,7 +40,7 @@ public async Task WhenPublicDelegate_ThenAlerts() { const string input = @"public delegate void ADelegate();"; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 1, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 1, 22, "ADelegate"); } @@ -49,7 +49,7 @@ public async Task WhenInternalDelegate_ThenAlerts() { const string input = @"internal delegate void ADelegate();"; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 1, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 1, 24, "ADelegate"); } @@ -61,7 +61,7 @@ public interface AnInterface { }"; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 2, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 2, 18, "AnInterface"); } @@ -73,7 +73,7 @@ internal interface AnInterface { }"; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 2, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 2, 20, "AnInterface"); } @@ -85,7 +85,7 @@ public enum AnEnum { }"; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 2, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 2, 13, "AnEnum"); } @@ -97,7 +97,7 @@ internal enum AnEnum { }"; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 2, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 2, 15, "AnEnum"); } @@ -109,7 +109,7 @@ public struct AStruct { }"; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 2, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 2, 15, "AStruct"); } @@ -121,7 +121,7 @@ internal struct AStruct { }"; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 2, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 2, 17, "AStruct"); } @@ -133,7 +133,7 @@ public readonly struct AStruct { }"; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 2, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 2, 24, "AStruct"); } @@ -145,7 +145,7 @@ internal readonly struct AStruct { }"; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 2, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 2, 26, "AStruct"); } @@ -157,7 +157,7 @@ public record ARecord() { }"; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 2, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 2, 15, "ARecord"); } @@ -169,7 +169,7 @@ internal record ARecord { }"; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 2, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 2, 17, "ARecord"); } @@ -182,7 +182,7 @@ public static class AClass } "; - await Verify.NoDiagnosticExists(input); + await Verify.NoDiagnosticExists(input); } [Fact] @@ -194,7 +194,7 @@ internal static class AClass } "; - await Verify.NoDiagnosticExists(input); + await Verify.NoDiagnosticExists(input); } [Fact] @@ -209,7 +209,7 @@ public static class AClass2 } "; - await Verify.NoDiagnosticExists(input); + await Verify.NoDiagnosticExists(input); } [Fact] @@ -227,7 +227,7 @@ private static class AClass2 } "; - await Verify.NoDiagnosticExists(input); + await Verify.NoDiagnosticExists(input); } [Fact] @@ -245,7 +245,7 @@ public class AClass2 } "; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 7, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 7, 18, "AClass2"); } @@ -264,7 +264,7 @@ private class AClass2 } "; - await Verify.NoDiagnosticExists(input); + await Verify.NoDiagnosticExists(input); } [Fact] @@ -276,7 +276,7 @@ public class AClass } "; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 2, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 2, 14, "AClass"); } @@ -289,7 +289,7 @@ public partial class AClass } "; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 2, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 2, 22, "AClass"); } @@ -305,9 +305,9 @@ public partial class AClass } "; - await Verify.DiagnosticExists(input, - (Platform_MissingDocsAnalyzer.Sas001, 2, 22, "AClass"), - (Platform_MissingDocsAnalyzer.Sas001, 5, 22, "AClass")); + await Verify.DiagnosticExists(input, + (MissingDocsAnalyzer.Sas001, 2, 22, "AClass"), + (MissingDocsAnalyzer.Sas001, 5, 22, "AClass")); } [Fact] @@ -319,7 +319,7 @@ internal class AClass } "; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 2, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 2, 16, "AClass"); } @@ -332,7 +332,7 @@ public class AClass } "; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 2, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 2, 14, "AClass"); } @@ -346,7 +346,7 @@ public class AClass } "; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 3, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 3, 14, "AClass"); } @@ -362,7 +362,7 @@ public class AClass } "; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 5, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 5, 14, "AClass"); } @@ -378,7 +378,7 @@ public class AClass } "; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 5, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 5, 14, "AClass"); } @@ -394,7 +394,7 @@ public class AClass } "; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 5, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 5, 14, "AClass"); } @@ -410,7 +410,7 @@ public class AClass } "; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas001, input, 5, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas001, input, 5, 14, "AClass"); } @@ -424,7 +424,7 @@ public class AClass } "; - await Verify.NoDiagnosticExists(input); + await Verify.NoDiagnosticExists(input); } [Fact] @@ -439,7 +439,7 @@ public class AClass } "; - await Verify.NoDiagnosticExists(input); + await Verify.NoDiagnosticExists(input); } [Fact] @@ -454,7 +454,7 @@ public partial class AClass } "; - await Verify.NoDiagnosticExists(input); + await Verify.NoDiagnosticExists(input); } [Fact] @@ -472,7 +472,7 @@ public partial class AClass } "; - await Verify.NoDiagnosticExists(input); + await Verify.NoDiagnosticExists(input); } } @@ -488,7 +488,7 @@ public static class AClass public static void AMethod(){} }"; - await Verify.NoDiagnosticExists(input); + await Verify.NoDiagnosticExists(input); } [Fact] @@ -500,7 +500,7 @@ public static class AClass public static void AMethod(){} }"; - await Verify.NoDiagnosticExists(input); + await Verify.NoDiagnosticExists(input); } [Fact] @@ -512,7 +512,7 @@ public static void AMethod1(){} public static void AMethod2(this string value){} }"; - await Verify.NoDiagnosticExists(input); + await Verify.NoDiagnosticExists(input); } [Fact] @@ -525,7 +525,7 @@ public static void AMethod(){} } "; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas002, input, 4, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas002, input, 4, 24, "AMethod"); } @@ -542,7 +542,7 @@ public static void AMethod(){} } "; - await Verify.NoDiagnosticExists(input); + await Verify.NoDiagnosticExists(input); } [Fact] @@ -555,7 +555,7 @@ internal static void AMethod(){} } "; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas002, input, 4, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas002, input, 4, 26, "AMethod"); } @@ -569,7 +569,7 @@ public static void AMethod(string value){} } "; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas002, input, 4, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas002, input, 4, 24, "AMethod"); } @@ -583,7 +583,7 @@ internal static void AMethod(string value){} } "; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas002, input, 4, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas002, input, 4, 26, "AMethod"); } @@ -597,7 +597,7 @@ internal static void AMethod(this string value){} } "; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas002, input, 4, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas002, input, 4, 26, "AMethod"); } @@ -611,7 +611,7 @@ private static void AMethod(this string value){} } "; - await Verify.NoDiagnosticExists(input); + await Verify.NoDiagnosticExists(input); } [Fact] @@ -624,7 +624,7 @@ public static void AMethod(this string value){} } "; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas002, input, 4, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas002, input, 4, 24, "AMethod"); } @@ -641,7 +641,7 @@ public static void AMethod(this string value){} } "; - await Verify.DiagnosticExists(Platform_MissingDocsAnalyzer.Sas002, input, 7, + await Verify.DiagnosticExists(MissingDocsAnalyzer.Sas002, input, 7, 24, "AMethod"); } @@ -658,7 +658,7 @@ public static void AMethod(this string value){} } "; - await Verify.NoDiagnosticExists(input); + await Verify.NoDiagnosticExists(input); } [Fact] @@ -672,7 +672,7 @@ public static void AMethod(this string value){} } "; - await Verify.NoDiagnosticExists(input); + await Verify.NoDiagnosticExists(input); } } } \ No newline at end of file diff --git a/src/Tools.Analyzers.Platform.UnitTests/Tools.Analyzers.Platform.UnitTests.csproj b/src/Tools.Analyzers.Platform.UnitTests/Tools.Analyzers.Platform.UnitTests.csproj index 52f79ddc..8eb8a209 100644 --- a/src/Tools.Analyzers.Platform.UnitTests/Tools.Analyzers.Platform.UnitTests.csproj +++ b/src/Tools.Analyzers.Platform.UnitTests/Tools.Analyzers.Platform.UnitTests.csproj @@ -8,14 +8,10 @@ - + - - - - diff --git a/src/Tools.Analyzers.Platform.UnitTests/Verify.cs b/src/Tools.Analyzers.Platform.UnitTests/Verify.cs index 7a87736b..f9e27340 100644 --- a/src/Tools.Analyzers.Platform.UnitTests/Verify.cs +++ b/src/Tools.Analyzers.Platform.UnitTests/Verify.cs @@ -1,6 +1,6 @@ extern alias CommonAnalyzers; +extern alias PlatformAnalyzers; using System.Reflection; -using Common.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Testing; using Microsoft.CodeAnalysis.Diagnostics; @@ -8,6 +8,7 @@ using NuGet.Frameworks; using AnalyzerConstants = CommonAnalyzers::Tools.Analyzers.Common.AnalyzerConstants; using Task = System.Threading.Tasks.Task; +using PlatformAnalyzers::Common.Extensions; namespace Tools.Analyzers.Platform.UnitTests; diff --git a/src/Tools.Analyzers.Platform/README.md b/src/Tools.Analyzers.Platform/README.md index 005032d6..c1491ccb 100644 --- a/src/Tools.Analyzers.Platform/README.md +++ b/src/Tools.Analyzers.Platform/README.md @@ -6,9 +6,12 @@ The individual analyzers will filter the individual projects their analyzers app # Development Workarounds +Roslyn Analyzers have to be built in NETSTANDARD2.0 for them to run in Visual Studio, but this is not the case to run in JetBrains Rider. +> This constraint exists to support analyzers working in older versions of the .NET Framework, and will exist until Microsoft fix the issue Visual Studio. This is another reason to use JetBrains Rider as the preferred IDE for working with this codebase. + C# Analyzers have difficulties running in the IDE if the code used in them has dependencies on other projects in the solution (and other nugets). -For example, referencing: `Tools.Analyzers.Common.csproj` +For example, referencing: `Common.csproj` This is especially problematic when those referenced projects have transient dependencies to types in AspNet (e.g., any project that has this reference: ``. diff --git a/src/Tools.Analyzers.Platform/Reference/System.Diagnostics.CodeAnalysis.cs b/src/Tools.Analyzers.Platform/Reference/System.Diagnostics.CodeAnalysis.cs new file mode 100644 index 00000000..aeb26de7 --- /dev/null +++ b/src/Tools.Analyzers.Platform/Reference/System.Diagnostics.CodeAnalysis.cs @@ -0,0 +1,30 @@ +#define INTERNAL_NULLABLE_ATTRIBUTES + +// ReSharper disable once CheckNamespace +namespace System.Diagnostics.CodeAnalysis; + +/// +/// HACK: This code is to enable the use of the '[NotNullWhen]' attribute that is not present in netstandard20 +/// Specifies that when a method returns , the parameter will not be null even if the +/// corresponding type allows it. +/// +[AttributeUsage(AttributeTargets.Parameter)] +#if INTERNAL_NULLABLE_ATTRIBUTES +internal +#else + public +#endif + sealed class NotNullWhenAttribute : Attribute +{ + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) + { + ReturnValue = returnValue; + } + + /// Gets the return value condition. + public bool ReturnValue { get; } +} \ No newline at end of file diff --git a/src/Tools.Analyzers.Platform/Tools.Analyzers.Platform.csproj b/src/Tools.Analyzers.Platform/Tools.Analyzers.Platform.csproj index d1e627a9..eb9dd8d3 100644 --- a/src/Tools.Analyzers.Platform/Tools.Analyzers.Platform.csproj +++ b/src/Tools.Analyzers.Platform/Tools.Analyzers.Platform.csproj @@ -1,14 +1,17 @@ - net8.0 + netstandard2.0 + $(DefineConstants);ANALYZERS_PLATFORM + latest + enable true true true - $(NoWarn),RS2007;NU5128 + $(NoWarn),RS2007,NU5128 @@ -28,6 +31,15 @@ + + + Reference\Common\Annotations.cs + + + Reference\Common\Extensions\ObjectExtensions.cs + + + ResXFileCodeGenerator @@ -43,9 +55,15 @@ - + $(GetTargetPathDependsOn);GetDependencyTargetPaths + <_TargetFramework>8.0.2 + <_AspNetFrameworkInstallFolder>C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\$(_TargetFramework) + <_FrameworkInstallFolder>C:\Program Files\dotnet\shared\Microsoft.NETCore.App\$(_TargetFramework) diff --git a/src/Tools.Generators.Common.UnitTests/FeatureFlagGeneratorSpec.cs b/src/Tools.Generators.Common.UnitTests/FeatureFlagGeneratorSpec.cs index 1933ed95..fd8cdd1e 100644 --- a/src/Tools.Generators.Common.UnitTests/FeatureFlagGeneratorSpec.cs +++ b/src/Tools.Generators.Common.UnitTests/FeatureFlagGeneratorSpec.cs @@ -1,11 +1,13 @@ +extern alias CommonGenerator; using System.Reflection; using System.Text; using FluentAssertions; -using JetBrains.Annotations; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Text; using Xunit; +using FeatureFlagGenerator = CommonGenerator::Tools.Generators.Common.FeatureFlagGenerator; +using UsedImplicitly = CommonGenerator::JetBrains.Annotations.UsedImplicitlyAttribute; namespace Tools.Generators.Common.UnitTests; diff --git a/src/Tools.Generators.Common.UnitTests/Tools.Generators.Common.UnitTests.csproj b/src/Tools.Generators.Common.UnitTests/Tools.Generators.Common.UnitTests.csproj index 3b406434..43f5c4a5 100644 --- a/src/Tools.Generators.Common.UnitTests/Tools.Generators.Common.UnitTests.csproj +++ b/src/Tools.Generators.Common.UnitTests/Tools.Generators.Common.UnitTests.csproj @@ -6,14 +6,11 @@ - - + + - - - diff --git a/src/Tools.Generators.Common/Reference/System.Diagnostics.CodeAnalysis.cs b/src/Tools.Generators.Common/Reference/System.Diagnostics.CodeAnalysis.cs new file mode 100644 index 00000000..aeb26de7 --- /dev/null +++ b/src/Tools.Generators.Common/Reference/System.Diagnostics.CodeAnalysis.cs @@ -0,0 +1,30 @@ +#define INTERNAL_NULLABLE_ATTRIBUTES + +// ReSharper disable once CheckNamespace +namespace System.Diagnostics.CodeAnalysis; + +/// +/// HACK: This code is to enable the use of the '[NotNullWhen]' attribute that is not present in netstandard20 +/// Specifies that when a method returns , the parameter will not be null even if the +/// corresponding type allows it. +/// +[AttributeUsage(AttributeTargets.Parameter)] +#if INTERNAL_NULLABLE_ATTRIBUTES +internal +#else + public +#endif + sealed class NotNullWhenAttribute : Attribute +{ + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) + { + ReturnValue = returnValue; + } + + /// Gets the return value condition. + public bool ReturnValue { get; } +} \ No newline at end of file diff --git a/src/Tools.Generators.Common/Tools.Generators.Common.csproj b/src/Tools.Generators.Common/Tools.Generators.Common.csproj index d6e5e61e..41853ee5 100644 --- a/src/Tools.Generators.Common/Tools.Generators.Common.csproj +++ b/src/Tools.Generators.Common/Tools.Generators.Common.csproj @@ -22,6 +22,9 @@ + + Reference\Common\Annotations.cs + Reference\Common\FeatureFlags\Flag.cs diff --git a/src/Tools.Generators.Web.Api.Authorization.UnitTests/AuthorizationAttributeGeneratorSpec.cs b/src/Tools.Generators.Web.Api.Authorization.UnitTests/AuthorizationAttributeGeneratorSpec.cs index 0d6a9357..e1bfd20d 100644 --- a/src/Tools.Generators.Web.Api.Authorization.UnitTests/AuthorizationAttributeGeneratorSpec.cs +++ b/src/Tools.Generators.Web.Api.Authorization.UnitTests/AuthorizationAttributeGeneratorSpec.cs @@ -1,9 +1,11 @@ +extern alias WebApiAuthorizationGenerator; using System.Reflection; using FluentAssertions; -using JetBrains.Annotations; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Xunit; +using AuthorizationAttributeGenerator = WebApiAuthorizationGenerator::Tools.Generators.Web.Api.Authorization.AuthorizationAttributeGenerator; +using UsedImplicitly = WebApiAuthorizationGenerator::JetBrains.Annotations.UsedImplicitlyAttribute; namespace Tools.Generators.Web.Api.Authorization.UnitTests; diff --git a/src/Tools.Generators.Web.Api.Authorization.UnitTests/Tools.Generators.Web.Api.Authorization.UnitTests.csproj b/src/Tools.Generators.Web.Api.Authorization.UnitTests/Tools.Generators.Web.Api.Authorization.UnitTests.csproj index 8789af64..979cadac 100644 --- a/src/Tools.Generators.Web.Api.Authorization.UnitTests/Tools.Generators.Web.Api.Authorization.UnitTests.csproj +++ b/src/Tools.Generators.Web.Api.Authorization.UnitTests/Tools.Generators.Web.Api.Authorization.UnitTests.csproj @@ -6,14 +6,11 @@ - - + + - - - diff --git a/src/Tools.Generators.Web.Api.Authorization/Reference/System.Diagnostics.CodeAnalysis.cs b/src/Tools.Generators.Web.Api.Authorization/Reference/System.Diagnostics.CodeAnalysis.cs new file mode 100644 index 00000000..aeb26de7 --- /dev/null +++ b/src/Tools.Generators.Web.Api.Authorization/Reference/System.Diagnostics.CodeAnalysis.cs @@ -0,0 +1,30 @@ +#define INTERNAL_NULLABLE_ATTRIBUTES + +// ReSharper disable once CheckNamespace +namespace System.Diagnostics.CodeAnalysis; + +/// +/// HACK: This code is to enable the use of the '[NotNullWhen]' attribute that is not present in netstandard20 +/// Specifies that when a method returns , the parameter will not be null even if the +/// corresponding type allows it. +/// +[AttributeUsage(AttributeTargets.Parameter)] +#if INTERNAL_NULLABLE_ATTRIBUTES +internal +#else + public +#endif + sealed class NotNullWhenAttribute : Attribute +{ + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) + { + ReturnValue = returnValue; + } + + /// Gets the return value condition. + public bool ReturnValue { get; } +} \ No newline at end of file diff --git a/src/Tools.Generators.Web.Api.Authorization/Tools.Generators.Web.Api.Authorization.csproj b/src/Tools.Generators.Web.Api.Authorization/Tools.Generators.Web.Api.Authorization.csproj index 4769c66e..c4653166 100644 --- a/src/Tools.Generators.Web.Api.Authorization/Tools.Generators.Web.Api.Authorization.csproj +++ b/src/Tools.Generators.Web.Api.Authorization/Tools.Generators.Web.Api.Authorization.csproj @@ -22,6 +22,9 @@ + + Reference\Common\Annotations.cs + Reference\Common\Extensions\CollectionExtensions.cs diff --git a/src/Tools.Generators.Web.Api.UnitTests/MinimalApiMediatRGeneratorSpec.cs b/src/Tools.Generators.Web.Api.UnitTests/MinimalApiMediatRGeneratorSpec.cs index 89660ffa..4194f1ee 100644 --- a/src/Tools.Generators.Web.Api.UnitTests/MinimalApiMediatRGeneratorSpec.cs +++ b/src/Tools.Generators.Web.Api.UnitTests/MinimalApiMediatRGeneratorSpec.cs @@ -1,11 +1,11 @@ extern alias Generators; using System.Reflection; using FluentAssertions; -using JetBrains.Annotations; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Xunit; using MinimalApiMediatRGenerator = Generators::Tools.Generators.Web.Api.MinimalApiMediatRGenerator; +using UsedImplicitly = Generators::JetBrains.Annotations.UsedImplicitlyAttribute; namespace Tools.Generators.Web.Api.UnitTests; diff --git a/src/Tools.Generators.Web.Api.UnitTests/Tools.Generators.Web.Api.UnitTests.csproj b/src/Tools.Generators.Web.Api.UnitTests/Tools.Generators.Web.Api.UnitTests.csproj index b8d69d3b..a1751be5 100644 --- a/src/Tools.Generators.Web.Api.UnitTests/Tools.Generators.Web.Api.UnitTests.csproj +++ b/src/Tools.Generators.Web.Api.UnitTests/Tools.Generators.Web.Api.UnitTests.csproj @@ -7,13 +7,10 @@ - + - - - diff --git a/src/Tools.Generators.Web.Api.UnitTests/WebApiAssemblyVisitorSpec.cs b/src/Tools.Generators.Web.Api.UnitTests/WebApiAssemblyVisitorSpec.cs index 5d2a570f..fccabb6d 100644 --- a/src/Tools.Generators.Web.Api.UnitTests/WebApiAssemblyVisitorSpec.cs +++ b/src/Tools.Generators.Web.Api.UnitTests/WebApiAssemblyVisitorSpec.cs @@ -2,7 +2,6 @@ using System.Collections.Immutable; using System.Reflection; using FluentAssertions; -using JetBrains.Annotations; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Moq; @@ -11,6 +10,7 @@ using IWebRequest = Generators::Infrastructure.Web.Api.Interfaces.IWebRequest; using ServiceOperation = Generators::Infrastructure.Web.Api.Interfaces.ServiceOperation; using WebApiAssemblyVisitor = Generators::Tools.Generators.Web.Api.WebApiAssemblyVisitor; +using UsedImplicitly = Generators::JetBrains.Annotations.UsedImplicitlyAttribute; namespace Tools.Generators.Web.Api.UnitTests; diff --git a/src/Tools.Generators.Web.Api/Reference/System.Diagnostics.CodeAnalysis.cs b/src/Tools.Generators.Web.Api/Reference/System.Diagnostics.CodeAnalysis.cs new file mode 100644 index 00000000..aeb26de7 --- /dev/null +++ b/src/Tools.Generators.Web.Api/Reference/System.Diagnostics.CodeAnalysis.cs @@ -0,0 +1,30 @@ +#define INTERNAL_NULLABLE_ATTRIBUTES + +// ReSharper disable once CheckNamespace +namespace System.Diagnostics.CodeAnalysis; + +/// +/// HACK: This code is to enable the use of the '[NotNullWhen]' attribute that is not present in netstandard20 +/// Specifies that when a method returns , the parameter will not be null even if the +/// corresponding type allows it. +/// +[AttributeUsage(AttributeTargets.Parameter)] +#if INTERNAL_NULLABLE_ATTRIBUTES +internal +#else + public +#endif + sealed class NotNullWhenAttribute : Attribute +{ + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) + { + ReturnValue = returnValue; + } + + /// Gets the return value condition. + public bool ReturnValue { get; } +} \ No newline at end of file diff --git a/src/Tools.Generators.Web.Api/Tools.Generators.Web.Api.csproj b/src/Tools.Generators.Web.Api/Tools.Generators.Web.Api.csproj index cbb3a3e2..578b6323 100644 --- a/src/Tools.Generators.Web.Api/Tools.Generators.Web.Api.csproj +++ b/src/Tools.Generators.Web.Api/Tools.Generators.Web.Api.csproj @@ -22,6 +22,9 @@ + + Reference\Common\Annotations.cs + Reference\Common\Extensions\StringExtensions.cs diff --git a/src/UnitTesting.CodeAnalysis.Common/UnitTesting.CodeAnalysis.Common.csproj b/src/UnitTesting.CodeAnalysis.Common/UnitTesting.CodeAnalysis.Common.csproj new file mode 100644 index 00000000..746fcd1a --- /dev/null +++ b/src/UnitTesting.CodeAnalysis.Common/UnitTesting.CodeAnalysis.Common.csproj @@ -0,0 +1,29 @@ + + + + net8.0 + true + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + +