diff --git a/build/targets/codeanalysis/.globalconfig b/build/targets/codeanalysis/.globalconfig index 0b6e8efa..2106bae7 100644 --- a/build/targets/codeanalysis/.globalconfig +++ b/build/targets/codeanalysis/.globalconfig @@ -7,3 +7,24 @@ is_global=true # AV2210 : Pass -warnaserror to the compiler or add True to your project file # This is set as part of the CI build. It is intentionally not set locally to allow for a fast inner dev loop. dotnet_diagnostic.AV2210.severity = none + +# Enable Effective C# Analyzers +dotnet_diagnostic.ECS0100.severity = warning +dotnet_diagnostic.ECS0200.severity = warning +dotnet_diagnostic.ECS0300.severity = warning +dotnet_diagnostic.ECS0400.severity = warning +dotnet_diagnostic.ECS0500.severity = warning +dotnet_diagnostic.ECS0600.severity = warning +dotnet_diagnostic.ECS0700.severity = warning +dotnet_diagnostic.ECS0800.severity = warning +dotnet_diagnostic.ECS0900.severity = warning +dotnet_diagnostic.ECS1000.severity = warning +dotnet_diagnostic.ECS1100.severity = warning +dotnet_diagnostic.ECS1200.severity = warning +dotnet_diagnostic.ECS1300.severity = warning +dotnet_diagnostic.ECS1400.severity = warning +dotnet_diagnostic.ECS1500.severity = warning +dotnet_diagnostic.ECS1600.severity = warning +dotnet_diagnostic.ECS1700.severity = warning +dotnet_diagnostic.ECS1800.severity = warning +dotnet_diagnostic.ECS1900.severity = warning diff --git a/build/targets/codeanalysis/CodeAnalysis.props b/build/targets/codeanalysis/CodeAnalysis.props index e83bbdce..fdd66631 100644 --- a/build/targets/codeanalysis/CodeAnalysis.props +++ b/build/targets/codeanalysis/CodeAnalysis.props @@ -39,5 +39,9 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/build/targets/codeanalysis/Packages.props b/build/targets/codeanalysis/Packages.props index b490b5b8..04febe30 100644 --- a/build/targets/codeanalysis/Packages.props +++ b/build/targets/codeanalysis/Packages.props @@ -8,5 +8,6 @@ + diff --git a/src/Moq.Analyzers/AsShouldBeUsedOnlyForInterfaceAnalyzer.cs b/src/Moq.Analyzers/AsShouldBeUsedOnlyForInterfaceAnalyzer.cs index fcaecd1f..c5f8bedb 100644 --- a/src/Moq.Analyzers/AsShouldBeUsedOnlyForInterfaceAnalyzer.cs +++ b/src/Moq.Analyzers/AsShouldBeUsedOnlyForInterfaceAnalyzer.cs @@ -8,8 +8,8 @@ namespace Moq.Analyzers; [DiagnosticAnalyzer(LanguageNames.CSharp)] public class AsShouldBeUsedOnlyForInterfaceAnalyzer : DiagnosticAnalyzer { - private const string Title = "Moq: Invalid As type parameter"; - private const string Message = "Mock.As() should take interfaces only"; + private static readonly LocalizableString Title = "Moq: Invalid As type parameter"; + private static readonly LocalizableString Message = "Mock.As() should take interfaces only"; private static readonly DiagnosticDescriptor Rule = new( DiagnosticIds.AsShouldOnlyBeUsedForInterfacesRuleId, @@ -42,11 +42,13 @@ private static void RegisterCompilationStartAction(CompilationStartAnalysisConte } // Look for the Mock.As() method and provide it to Analyze to avoid looking it up multiple times. +#pragma warning disable ECS0900 // Minimize boxing and unboxing ImmutableArray asMethods = mockTypes .SelectMany(mockType => mockType.GetMembers(WellKnownTypeNames.As)) .OfType() .Where(method => method.IsGenericMethod) .ToImmutableArray(); +#pragma warning restore ECS0900 // Minimize boxing and unboxing if (asMethods.IsEmpty) { @@ -66,10 +68,12 @@ private static void Analyze(OperationAnalysisContext context, ImmutableArray typeArguments = targetMethod.TypeArguments; if (typeArguments.Length != 1) diff --git a/src/Moq.Analyzers/CallbackSignatureShouldMatchMockedMethodAnalyzer.cs b/src/Moq.Analyzers/CallbackSignatureShouldMatchMockedMethodAnalyzer.cs index 90a4d0e0..ead2b873 100644 --- a/src/Moq.Analyzers/CallbackSignatureShouldMatchMockedMethodAnalyzer.cs +++ b/src/Moq.Analyzers/CallbackSignatureShouldMatchMockedMethodAnalyzer.cs @@ -6,24 +6,20 @@ namespace Moq.Analyzers; [DiagnosticAnalyzer(LanguageNames.CSharp)] public class CallbackSignatureShouldMatchMockedMethodAnalyzer : DiagnosticAnalyzer { - internal const string RuleId = DiagnosticIds.BadCallbackParameters; - private const string Title = "Moq: Bad callback parameters"; - private const string Message = "Callback signature must match the signature of the mocked method"; + private static readonly LocalizableString Title = "Moq: Bad callback parameters"; + private static readonly LocalizableString Message = "Callback signature must match the signature of the mocked method"; private static readonly DiagnosticDescriptor Rule = new( - RuleId, + DiagnosticIds.BadCallbackParameters, Title, Message, DiagnosticCategory.Moq, DiagnosticSeverity.Warning, isEnabledByDefault: true, - helpLinkUri: $"https://github.com/rjmurillo/moq.analyzers/blob/{ThisAssembly.GitCommitId}/docs/rules/{RuleId}.md"); + helpLinkUri: $"https://github.com/rjmurillo/moq.analyzers/blob/{ThisAssembly.GitCommitId}/docs/rules/{DiagnosticIds.BadCallbackParameters}.md"); /// - public override ImmutableArray SupportedDiagnostics - { - get { return ImmutableArray.Create(Rule); } - } + public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Rule); /// public override void Initialize(AnalysisContext context) diff --git a/src/Moq.Analyzers/CallbackSignatureShouldMatchMockedMethodCodeFix.cs b/src/Moq.Analyzers/CallbackSignatureShouldMatchMockedMethodCodeFix.cs index d84e6b2d..7afedde0 100644 --- a/src/Moq.Analyzers/CallbackSignatureShouldMatchMockedMethodCodeFix.cs +++ b/src/Moq.Analyzers/CallbackSignatureShouldMatchMockedMethodCodeFix.cs @@ -14,16 +14,10 @@ namespace Moq.Analyzers; public class CallbackSignatureShouldMatchMockedMethodCodeFix : CodeFixProvider { /// - public sealed override ImmutableArray FixableDiagnosticIds - { - get { return ImmutableArray.Create(CallbackSignatureShouldMatchMockedMethodAnalyzer.RuleId); } - } + public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DiagnosticIds.BadCallbackParameters); /// - public sealed override FixAllProvider GetFixAllProvider() - { - return WellKnownFixAllProviders.BatchFixer; - } + public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; /// public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) diff --git a/src/Moq.Analyzers/Common/ArrayExtensions.cs b/src/Moq.Analyzers/Common/ArrayExtensions.cs new file mode 100644 index 00000000..eb19cfa0 --- /dev/null +++ b/src/Moq.Analyzers/Common/ArrayExtensions.cs @@ -0,0 +1,53 @@ +using ArgumentOutOfRangeException = System.ArgumentOutOfRangeException; + +namespace Moq.Analyzers.Common; + +internal static class ArrayExtensions +{ + /// + /// Returns an array with the element at the specified position removed. + /// + /// The array type. + /// The array. + /// The 0-based index into the array for the element to omit from the returned array. + /// The new array. + internal static T[] RemoveAt(this T[] array, int index) + { + return RemoveRange(array, index, 1); + } + + /// + /// Returns an array with the elements at the specified position removed. + /// + /// The array type. + /// The array. + /// The 0-based index into the array for the element to omit from the returned array. + /// The number of elements to remove. + /// The new array. + private static T[] RemoveRange(this T[] array, int index, int length) + { + // Range check + if (index < 0 || index >= array.Length) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + + if (length < 0 || index + length > array.Length) + { + throw new ArgumentOutOfRangeException(nameof(length)); + } + +#pragma warning disable S2583 // Change condition so it doesn't always evaluate to false + if (array.Length == 0) +#pragma warning restore S2583 + { + return array; + } + + T[] tmp = new T[array.Length - length]; + Array.Copy(array, tmp, index); + Array.Copy(array, index + length, tmp, index, array.Length - index - length); + + return tmp; + } +} diff --git a/src/Moq.Analyzers/Common/DiagnosticCategory.cs b/src/Moq.Analyzers/Common/DiagnosticCategory.cs index 34f922e0..9907bdc1 100644 --- a/src/Moq.Analyzers/Common/DiagnosticCategory.cs +++ b/src/Moq.Analyzers/Common/DiagnosticCategory.cs @@ -1,5 +1,7 @@ namespace Moq.Analyzers.Common; +#pragma warning disable ECS0200 // Consider using readonly instead of const for flexibility + internal static class DiagnosticCategory { internal const string Moq = nameof(Moq); diff --git a/src/Moq.Analyzers/Common/DiagnosticExtensions.cs b/src/Moq.Analyzers/Common/DiagnosticExtensions.cs index 596d9a8e..562ac267 100644 --- a/src/Moq.Analyzers/Common/DiagnosticExtensions.cs +++ b/src/Moq.Analyzers/Common/DiagnosticExtensions.cs @@ -13,12 +13,12 @@ public static Diagnostic CreateDiagnostic( DiagnosticDescriptor rule, ImmutableDictionary? properties, params object?[]? messageArgs) - => node.CreateDiagnostic(rule, additionalLocations: ImmutableArray.Empty, properties, messageArgs); + => node.CreateDiagnostic(rule, additionalLocations: Array.Empty(), properties, messageArgs); public static Diagnostic CreateDiagnostic( this SyntaxNode node, DiagnosticDescriptor rule, - ImmutableArray additionalLocations, + IEnumerable? additionalLocations, ImmutableDictionary? properties, params object?[]? messageArgs) => node @@ -44,12 +44,12 @@ public static Diagnostic CreateDiagnostic( DiagnosticDescriptor rule, ImmutableDictionary? properties, params object?[]? messageArgs) - => location.CreateDiagnostic(rule, ImmutableArray.Empty, properties, messageArgs); + => location.CreateDiagnostic(rule, Array.Empty(), properties, messageArgs); public static Diagnostic CreateDiagnostic( this Location location, DiagnosticDescriptor rule, - ImmutableArray additionalLocations, + IEnumerable? additionalLocations, ImmutableDictionary? properties, params object?[]? messageArgs) { diff --git a/src/Moq.Analyzers/Common/DiagnosticIds.cs b/src/Moq.Analyzers/Common/DiagnosticIds.cs index 9807c038..8e143e18 100644 --- a/src/Moq.Analyzers/Common/DiagnosticIds.cs +++ b/src/Moq.Analyzers/Common/DiagnosticIds.cs @@ -1,5 +1,7 @@ namespace Moq.Analyzers.Common; +#pragma warning disable ECS0200 // Consider using readonly instead of const for flexibility + internal static class DiagnosticIds { internal const string SealedClassCannotBeMocked = "Moq1000"; diff --git a/src/Moq.Analyzers/Common/MoqMethodDescriptorBase.cs b/src/Moq.Analyzers/Common/MoqMethodDescriptorBase.cs index 7111ad57..26392264 100644 --- a/src/Moq.Analyzers/Common/MoqMethodDescriptorBase.cs +++ b/src/Moq.Analyzers/Common/MoqMethodDescriptorBase.cs @@ -11,28 +11,16 @@ /// internal abstract class MoqMethodDescriptorBase { - private const string ContainingNamespace = WellKnownTypeNames.Moq; - private const string ContainingType = WellKnownTypeNames.MockName; + private static readonly string ContainingNamespace = WellKnownTypeNames.Moq; + private static readonly string ContainingType = WellKnownTypeNames.MockName; public abstract bool IsMatch(SemanticModel semanticModel, MemberAccessExpressionSyntax memberAccessSyntax, CancellationToken cancellationToken); - protected static bool IsFastMatch(MemberAccessExpressionSyntax memberAccessSyntax, ReadOnlySpan methodName) - { - return memberAccessSyntax.Name.Identifier.Text.AsSpan().SequenceEqual(methodName); - } + protected static bool IsFastMatch(MemberAccessExpressionSyntax memberAccessSyntax, ReadOnlySpan methodName) => memberAccessSyntax.Name.Identifier.Text.AsSpan().SequenceEqual(methodName); - protected static bool IsContainedInMockType(IMethodSymbol methodSymbol) - { - return IsInMoqNamespace(methodSymbol) && IsInMockType(methodSymbol); - } + protected static bool IsContainedInMockType(IMethodSymbol methodSymbol) => IsInMoqNamespace(methodSymbol) && IsInMockType(methodSymbol); - private static bool IsInMoqNamespace(ISymbol symbol) - { - return symbol.ContainingNamespace.Name.AsSpan().SequenceEqual(ContainingNamespace.AsSpan()); - } + private static bool IsInMoqNamespace(ISymbol symbol) => symbol.ContainingNamespace.Name.AsSpan().SequenceEqual(ContainingNamespace.AsSpan()); - private static bool IsInMockType(ISymbol symbol) - { - return symbol.ContainingType.Name.AsSpan().SequenceEqual(ContainingType.AsSpan()); - } + private static bool IsInMockType(ISymbol symbol) => symbol.ContainingType.Name.AsSpan().SequenceEqual(ContainingType.AsSpan()); } diff --git a/src/Moq.Analyzers/Common/WellKnownTypeNames.cs b/src/Moq.Analyzers/Common/WellKnownTypeNames.cs index 4ebeeb8f..e47bc65d 100644 --- a/src/Moq.Analyzers/Common/WellKnownTypeNames.cs +++ b/src/Moq.Analyzers/Common/WellKnownTypeNames.cs @@ -1,16 +1,18 @@ namespace Moq.Analyzers.Common; +#pragma warning disable ECS0200 // Consider using readonly instead of const for flexibility + internal static class WellKnownTypeNames { - internal const string Moq = "Moq"; + internal const string Moq = nameof(Moq); internal const string MockName = "Mock"; - internal const string MockBehavior = "MockBehavior"; - internal const string MockFactory = "MockFactory"; + internal const string MockBehavior = nameof(MockBehavior); + internal const string MockFactory = nameof(MockFactory); internal const string MoqMock = $"{Moq}.{MockName}"; internal const string MoqMock1 = $"{MoqMock}`1"; internal const string MoqBehavior = $"{Moq}.{MockBehavior}"; internal const string MoqRepository = $"{Moq}.MockRepository"; - internal const string As = "As"; - internal const string Create = "Create"; - internal const string Of = "Of"; + internal const string As = nameof(As); + internal const string Create = nameof(Create); + internal const string Of = nameof(Of); } diff --git a/src/Moq.Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs b/src/Moq.Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs index 5c9c23e8..5b89efa5 100644 --- a/src/Moq.Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs +++ b/src/Moq.Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs @@ -132,7 +132,7 @@ private static bool IsFirstArgumentMockBehavior(SyntaxNodeAnalysisContext contex private static void VerifyDelegateMockAttempt( SyntaxNodeAnalysisContext context, ArgumentListSyntax? argumentList, - ImmutableArray arguments) + ArgumentSyntax[] arguments) { if (arguments.Length == 0) { @@ -149,7 +149,7 @@ private static void VerifyDelegateMockAttempt( private static void VerifyInterfaceMockAttempt( SyntaxNodeAnalysisContext context, ArgumentListSyntax? argumentList, - ImmutableArray arguments) + ArgumentSyntax[] arguments) { // Interfaces and delegates don't have ctors, so bail out early if (arguments.Length == 0) @@ -322,8 +322,8 @@ private static void AnalyzeNewObject(SyntaxNodeAnalysisContext context) /// Handles and optional parameters. [SuppressMessage("Design", "MA0051:Method is too long", Justification = "This should be refactored; suppressing for now to enable TreatWarningsAsErrors in CI.")] private static bool AnyConstructorsFound( - ImmutableArray constructors, - ImmutableArray arguments, + IMethodSymbol[] constructors, + ArgumentSyntax[] arguments, SyntaxNodeAnalysisContext context) { for (int constructorIndex = 0; constructorIndex < constructors.Length; constructorIndex++) @@ -331,7 +331,9 @@ private static bool AnyConstructorsFound( IMethodSymbol constructor = constructors[constructorIndex]; bool hasParams = constructor.Parameters.Length > 0 && constructor.Parameters[^1].IsParams; int fixedParametersCount = hasParams ? constructor.Parameters.Length - 1 : constructor.Parameters.Length; +#pragma warning disable ECS0900 // Consider using an alternative implementation to avoid boxing and unboxing int requiredParameters = constructor.Parameters.Count(parameterSymbol => !parameterSymbol.IsOptional); +#pragma warning restore ECS0900 // Consider using an alternative implementation to avoid boxing and unboxing bool allParametersMatch = true; // Check if the number of arguments is valid considering params @@ -401,7 +403,7 @@ private static bool AnyConstructorsFound( } private static (bool IsEmpty, Location Location) ConstructorIsEmpty( - ImmutableArray constructors, + IMethodSymbol[] constructors, ArgumentListSyntax? argumentList, SyntaxNodeAnalysisContext context) { @@ -416,7 +418,7 @@ private static (bool IsEmpty, Location Location) ConstructorIsEmpty( location = context.Node.GetLocation(); } - return (constructors.IsEmpty, location); + return (constructors.Length == 0, location); } private static void VerifyMockAttempt( @@ -430,9 +432,9 @@ private static void VerifyMockAttempt( return; } - ImmutableArray arguments = - argumentList?.Arguments.ToImmutableArray() - ?? ImmutableArray.Empty; +#pragma warning disable ECS0900 // Consider using an alternative implementation to avoid boxing and unboxing + ArgumentSyntax[] arguments = argumentList?.Arguments.ToArray() ?? []; +#pragma warning restore ECS0900 // Consider using an alternative implementation to avoid boxing and unboxing if (hasMockBehavior && arguments.Length > 0 && IsFirstArgumentMockBehavior(context, argumentList)) { @@ -463,13 +465,13 @@ private static void VerifyClassMockAttempt( SyntaxNodeAnalysisContext context, ITypeSymbol mockedClass, ArgumentListSyntax? argumentList, - ImmutableArray arguments) + ArgumentSyntax[] arguments) { - ImmutableArray constructors = mockedClass + IMethodSymbol[] constructors = mockedClass .GetMembers() .OfType() .Where(methodSymbol => methodSymbol.IsConstructor()) - .ToImmutableArray(); + .ToArray(); // Bail out early if there are no arguments on constructors or no constructors at all (bool IsEmpty, Location Location) constructorIsEmpty = ConstructorIsEmpty(constructors, argumentList, context); diff --git a/src/Moq.Analyzers/MoqSetupMethodDescriptor.cs b/src/Moq.Analyzers/MoqSetupMethodDescriptor.cs index 9ca4f1ad..ee81d8dc 100644 --- a/src/Moq.Analyzers/MoqSetupMethodDescriptor.cs +++ b/src/Moq.Analyzers/MoqSetupMethodDescriptor.cs @@ -6,7 +6,7 @@ /// internal class MoqSetupMethodDescriptor : MoqMethodDescriptorBase { - private const string MethodName = "Setup"; + private static readonly string MethodName = "Setup"; [System.Diagnostics.CodeAnalysis.SuppressMessage("Maintainability", "AV1500:Member or local function contains too many statements", Justification = "Tracked in https://github.com/rjmurillo/moq.analyzers/issues/90")] public override bool IsMatch(SemanticModel semanticModel, MemberAccessExpressionSyntax memberAccessSyntax, CancellationToken cancellationToken) diff --git a/src/Moq.Analyzers/NoMethodsInPropertySetupAnalyzer.cs b/src/Moq.Analyzers/NoMethodsInPropertySetupAnalyzer.cs index c5d8cfbf..c5545803 100644 --- a/src/Moq.Analyzers/NoMethodsInPropertySetupAnalyzer.cs +++ b/src/Moq.Analyzers/NoMethodsInPropertySetupAnalyzer.cs @@ -6,18 +6,17 @@ namespace Moq.Analyzers; [DiagnosticAnalyzer(LanguageNames.CSharp)] public class NoMethodsInPropertySetupAnalyzer : DiagnosticAnalyzer { - internal const string RuleId = DiagnosticIds.PropertySetupUsedForMethod; - private const string Title = "Moq: Property setup used for a method"; - private const string Message = "SetupGet/SetupSet should be used for properties, not for methods"; + private static readonly LocalizableString Title = "Moq: Property setup used for a method"; + private static readonly LocalizableString Message = "SetupGet/SetupSet should be used for properties, not for methods"; private static readonly DiagnosticDescriptor Rule = new( - RuleId, + DiagnosticIds.PropertySetupUsedForMethod, Title, Message, DiagnosticCategory.Moq, DiagnosticSeverity.Warning, isEnabledByDefault: true, - helpLinkUri: $"https://github.com/rjmurillo/moq.analyzers/blob/{ThisAssembly.GitCommitId}/docs/rules/{RuleId}.md"); + helpLinkUri: $"https://github.com/rjmurillo/moq.analyzers/blob/{ThisAssembly.GitCommitId}/docs/rules/{DiagnosticIds.PropertySetupUsedForMethod}.md"); /// public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Rule); diff --git a/src/Moq.Analyzers/NoSealedClassMocksAnalyzer.cs b/src/Moq.Analyzers/NoSealedClassMocksAnalyzer.cs index b44d616e..63642004 100644 --- a/src/Moq.Analyzers/NoSealedClassMocksAnalyzer.cs +++ b/src/Moq.Analyzers/NoSealedClassMocksAnalyzer.cs @@ -6,18 +6,17 @@ namespace Moq.Analyzers; [DiagnosticAnalyzer(LanguageNames.CSharp)] public class NoSealedClassMocksAnalyzer : DiagnosticAnalyzer { - internal const string RuleId = DiagnosticIds.SealedClassCannotBeMocked; - private const string Title = "Moq: Sealed class mocked"; - private const string Message = "Sealed classes cannot be mocked"; + private static readonly LocalizableString Title = "Moq: Sealed class mocked"; + private static readonly LocalizableString Message = "Sealed classes cannot be mocked"; private static readonly DiagnosticDescriptor Rule = new( - RuleId, + DiagnosticIds.SealedClassCannotBeMocked, Title, Message, DiagnosticCategory.Moq, DiagnosticSeverity.Warning, isEnabledByDefault: true, - helpLinkUri: $"https://github.com/rjmurillo/moq.analyzers/blob/{ThisAssembly.GitCommitId}/docs/rules/{RuleId}.md"); + helpLinkUri: $"https://github.com/rjmurillo/moq.analyzers/blob/{ThisAssembly.GitCommitId}/docs/rules/{DiagnosticIds.SealedClassCannotBeMocked}.md"); /// public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Rule); diff --git a/src/Moq.Analyzers/SetupShouldBeUsedOnlyForOverridableMembersAnalyzer.cs b/src/Moq.Analyzers/SetupShouldBeUsedOnlyForOverridableMembersAnalyzer.cs index 6d851eda..9e058440 100644 --- a/src/Moq.Analyzers/SetupShouldBeUsedOnlyForOverridableMembersAnalyzer.cs +++ b/src/Moq.Analyzers/SetupShouldBeUsedOnlyForOverridableMembersAnalyzer.cs @@ -6,18 +6,17 @@ namespace Moq.Analyzers; [DiagnosticAnalyzer(LanguageNames.CSharp)] public class SetupShouldBeUsedOnlyForOverridableMembersAnalyzer : DiagnosticAnalyzer { - internal const string RuleId = DiagnosticIds.SetupOnlyUsedForOverridableMembers; - private const string Title = "Moq: Invalid setup parameter"; - private const string Message = "Setup should be used only for overridable members"; + private static readonly LocalizableString Title = "Moq: Invalid setup parameter"; + private static readonly LocalizableString Message = "Setup should be used only for overridable members"; private static readonly DiagnosticDescriptor Rule = new( - RuleId, + DiagnosticIds.SetupOnlyUsedForOverridableMembers, Title, Message, DiagnosticCategory.Moq, DiagnosticSeverity.Error, isEnabledByDefault: true, - helpLinkUri: $"https://github.com/rjmurillo/moq.analyzers/blob/{ThisAssembly.GitCommitId}/docs/rules/{RuleId}.md"); + helpLinkUri: $"https://github.com/rjmurillo/moq.analyzers/blob/{ThisAssembly.GitCommitId}/docs/rules/{DiagnosticIds.SetupOnlyUsedForOverridableMembers}.md"); /// public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Rule); diff --git a/src/Moq.Analyzers/SetupShouldNotIncludeAsyncResultAnalyzer.cs b/src/Moq.Analyzers/SetupShouldNotIncludeAsyncResultAnalyzer.cs index 642bf63d..8489fabd 100644 --- a/src/Moq.Analyzers/SetupShouldNotIncludeAsyncResultAnalyzer.cs +++ b/src/Moq.Analyzers/SetupShouldNotIncludeAsyncResultAnalyzer.cs @@ -6,18 +6,17 @@ [DiagnosticAnalyzer(LanguageNames.CSharp)] public class SetupShouldNotIncludeAsyncResultAnalyzer : DiagnosticAnalyzer { - internal const string RuleId = DiagnosticIds.AsyncUsesReturnsAsyncInsteadOfResult; - private const string Title = "Moq: Invalid setup parameter"; - private const string Message = "Setup of async methods should use ReturnsAsync instead of .Result"; + private static readonly LocalizableString Title = "Moq: Invalid setup parameter"; + private static readonly LocalizableString Message = "Setup of async methods should use ReturnsAsync instead of .Result"; private static readonly DiagnosticDescriptor Rule = new( - RuleId, + DiagnosticIds.AsyncUsesReturnsAsyncInsteadOfResult, Title, Message, DiagnosticCategory.Moq, DiagnosticSeverity.Error, isEnabledByDefault: true, - helpLinkUri: $"https://github.com/rjmurillo/moq.analyzers/blob/{ThisAssembly.GitCommitId}/docs/rules/{RuleId}.md"); + helpLinkUri: $"https://github.com/rjmurillo/moq.analyzers/blob/{ThisAssembly.GitCommitId}/docs/rules/{DiagnosticIds.AsyncUsesReturnsAsyncInsteadOfResult}.md"); /// public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Rule); diff --git a/src/Moq.Analyzers/SquiggleCop.Baseline.yaml b/src/Moq.Analyzers/SquiggleCop.Baseline.yaml index 7989daec..39400c30 100644 --- a/src/Moq.Analyzers/SquiggleCop.Baseline.yaml +++ b/src/Moq.Analyzers/SquiggleCop.Baseline.yaml @@ -35,7 +35,7 @@ - {Id: CA1056, Title: URI-like properties should not be strings, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA1058, Title: Types should not extend certain base types, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA1060, Title: Move pinvokes to native methods class, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} -- {Id: CA1061, Title: Do not hide base class methods, Category: Design, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: CA1061, Title: Do not hide base class methods, Category: Design, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: CA1062, Title: Validate arguments of public methods, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA1063, Title: Implement IDisposable Correctly, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA1064, Title: Exceptions should be public, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} @@ -298,6 +298,14 @@ - {Id: CA5403, Title: Do not hard-code certificate, Category: Security, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA5404, Title: Do not disable token validation checks, Category: Security, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA5405, Title: Do not always skip token validation in delegates, Category: Security, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} +- {Id: ECS0100, Title: Prefer implicitly typed local variables, Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: ECS0200, Title: Prefer readonly over const, Category: Maintainability, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: true} +- {Id: ECS0400, Title: Replace string.Format with interpolated string, Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: ECS0500, Title: Prefer FormattableString or string.Create for culture-specific strings, Category: Globalization, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: ECS0600, Title: Avoid stringly-typed APIs, Category: Refactoring, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: ECS0700, Title: Express callbacks with delegates, Category: Design, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: ECS0800, Title: Use the Null Conditional Operator for Event Invocations, Category: Usage, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: ECS0900, Title: Minimize boxing and unboxing, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: true} - {Id: EM0001, Title: Switch on Enum Not Exhaustive, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: EM0002, Title: Switch on Nullable Enum Not Exhaustive, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: EM0003, Title: Switch on Closed Type Not Exhaustive, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} @@ -1022,7 +1030,7 @@ - {Id: S2479, Title: Whitespace and control characters in string literals should be explicit, Category: Critical Code Smell, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: S2486, Title: Generic exceptions should not be ignored, Category: Minor Code Smell, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: S2551, Title: Shared resources should not be used for locking, Category: Critical Bug, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} -- {Id: S2583, Title: Conditionally executed code should be reachable, Category: Major Bug, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: S2583, Title: Conditionally executed code should be reachable, Category: Major Bug, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: true} - {Id: S2589, Title: Boolean expressions should not be gratuitous, Category: Major Code Smell, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: true} - {Id: S2612, Title: Setting loose file permissions is security-sensitive, Category: Major Security Hotspot, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: S2629, Title: Logging templates should be constant, Category: Major Code Smell, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} diff --git a/src/tools/PerfDiff/.editorconfig b/src/tools/PerfDiff/.editorconfig index 7324b7e2..2cf1d833 100644 --- a/src/tools/PerfDiff/.editorconfig +++ b/src/tools/PerfDiff/.editorconfig @@ -112,3 +112,24 @@ dotnet_diagnostic.MA0076.severity = none dotnet_diagnostic.RCS1192.severity = none # S1135: Track uses of "TODO" tags dotnet_diagnostic.S1135.severity = none + +# Enable Effective C# Analyzers +dotnet_diagnostic.ECS0100.severity = none +dotnet_diagnostic.ECS0200.severity = none +dotnet_diagnostic.ECS0300.severity = none +dotnet_diagnostic.ECS0400.severity = none +dotnet_diagnostic.ECS0500.severity = none +dotnet_diagnostic.ECS0600.severity = none +dotnet_diagnostic.ECS0700.severity = none +dotnet_diagnostic.ECS0800.severity = none +dotnet_diagnostic.ECS0900.severity = none +dotnet_diagnostic.ECS1000.severity = none +dotnet_diagnostic.ECS1100.severity = none +dotnet_diagnostic.ECS1200.severity = none +dotnet_diagnostic.ECS1300.severity = none +dotnet_diagnostic.ECS1400.severity = none +dotnet_diagnostic.ECS1500.severity = none +dotnet_diagnostic.ECS1600.severity = none +dotnet_diagnostic.ECS1700.severity = none +dotnet_diagnostic.ECS1800.severity = none +dotnet_diagnostic.ECS1900.severity = none diff --git a/src/tools/PerfDiff/SquiggleCop.Baseline.yaml b/src/tools/PerfDiff/SquiggleCop.Baseline.yaml index fc3c8dbd..8937fe75 100644 --- a/src/tools/PerfDiff/SquiggleCop.Baseline.yaml +++ b/src/tools/PerfDiff/SquiggleCop.Baseline.yaml @@ -35,7 +35,7 @@ - {Id: CA1056, Title: URI-like properties should not be strings, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA1058, Title: Types should not extend certain base types, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA1060, Title: Move pinvokes to native methods class, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} -- {Id: CA1061, Title: Do not hide base class methods, Category: Design, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: CA1061, Title: Do not hide base class methods, Category: Design, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: CA1062, Title: Validate arguments of public methods, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA1063, Title: Implement IDisposable Correctly, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA1064, Title: Exceptions should be public, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} @@ -298,6 +298,14 @@ - {Id: CA5403, Title: Do not hard-code certificate, Category: Security, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA5404, Title: Do not disable token validation checks, Category: Security, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA5405, Title: Do not always skip token validation in delegates, Category: Security, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} +- {Id: ECS0100, Title: Prefer implicitly typed local variables, Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error, None], IsEverSuppressed: true} +- {Id: ECS0200, Title: Prefer readonly over const, Category: Maintainability, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error, None], IsEverSuppressed: true} +- {Id: ECS0400, Title: Replace string.Format with interpolated string, Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error, None], IsEverSuppressed: true} +- {Id: ECS0500, Title: Prefer FormattableString or string.Create for culture-specific strings, Category: Globalization, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error, None], IsEverSuppressed: true} +- {Id: ECS0600, Title: Avoid stringly-typed APIs, Category: Refactoring, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error, None], IsEverSuppressed: true} +- {Id: ECS0700, Title: Express callbacks with delegates, Category: Design, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error, None], IsEverSuppressed: true} +- {Id: ECS0800, Title: Use the Null Conditional Operator for Event Invocations, Category: Usage, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error, None], IsEverSuppressed: true} +- {Id: ECS0900, Title: Minimize boxing and unboxing, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error, None], IsEverSuppressed: true} - {Id: EM0001, Title: Switch on Enum Not Exhaustive, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: EM0002, Title: Switch on Nullable Enum Not Exhaustive, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: EM0003, Title: Switch on Closed Type Not Exhaustive, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} diff --git a/tests/Moq.Analyzers.Benchmarks/Constants.cs b/tests/Moq.Analyzers.Benchmarks/Constants.cs index 338f9f04..6070a45d 100644 --- a/tests/Moq.Analyzers.Benchmarks/Constants.cs +++ b/tests/Moq.Analyzers.Benchmarks/Constants.cs @@ -1,5 +1,7 @@ namespace Moq.Analyzers.Benchmarks; +#pragma warning disable ECS0200 // Consider using readonly instead of const for flexibility + internal static class Constants { public const int NumberOfCodeFiles = 1_000; diff --git a/tests/Moq.Analyzers.Benchmarks/Helpers/CompilationCreator.cs b/tests/Moq.Analyzers.Benchmarks/Helpers/CompilationCreator.cs index d3c73a03..3840df2f 100644 --- a/tests/Moq.Analyzers.Benchmarks/Helpers/CompilationCreator.cs +++ b/tests/Moq.Analyzers.Benchmarks/Helpers/CompilationCreator.cs @@ -100,7 +100,9 @@ private static async Task CreateSolutionAsync( async () => { AttributedPartDiscovery discovery = new(Resolver.DefaultInstance, isNonPublicSupported: true); +#pragma warning disable ECS0900 // Minimize boxing and unboxing DiscoveredParts parts = await discovery.CreatePartsAsync(MefHostServices.DefaultAssemblies).ConfigureAwait(false); +#pragma warning restore ECS0900 // Minimize boxing and unboxing ComposableCatalog catalog = ComposableCatalog.Create(Resolver.DefaultInstance).AddParts(parts); CompositionConfiguration configuration = CompositionConfiguration.Create(catalog); @@ -119,7 +121,9 @@ private static async Task CreateSolutionAsync( .WithProjectParseOptions(projectId, parseOptions); ImmutableArray metadataReferences = await referenceAssemblies.ResolveAsync(projectState.Language, CancellationToken.None).ConfigureAwait(false); +#pragma warning disable ECS0900 // Minimize boxing and unboxing solution = solution.AddMetadataReferences(projectId, metadataReferences); +#pragma warning restore ECS0900 // Minimize boxing and unboxing return solution; } diff --git a/tests/Moq.Analyzers.Benchmarks/Helpers/ExportProviderExtensions.cs b/tests/Moq.Analyzers.Benchmarks/Helpers/ExportProviderExtensions.cs index 57323710..216721de 100644 --- a/tests/Moq.Analyzers.Benchmarks/Helpers/ExportProviderExtensions.cs +++ b/tests/Moq.Analyzers.Benchmarks/Helpers/ExportProviderExtensions.cs @@ -27,7 +27,9 @@ public CompositionContextShim(ExportProvider exportProvider) [SuppressMessage("Maintainability", "AV1500:Member or local function contains too many statements", Justification = "Minimizing divergence from upstream")] public override bool TryGetExport(CompositionContract contract, [NotNullWhen(true)] out object? export) { +#pragma warning disable ECS0900 // Minimize boxing and unboxing bool importMany = contract.MetadataConstraints.Contains(new KeyValuePair("IsImportMany", true)); +#pragma warning restore ECS0900 // Minimize boxing and unboxing (Type contractType, Type? metadataType) = GetContractType(contract.ContractType, importMany); if (metadataType != null) diff --git a/tests/Moq.Analyzers.Benchmarks/SquiggleCop.Baseline.yaml b/tests/Moq.Analyzers.Benchmarks/SquiggleCop.Baseline.yaml index c3579d00..f5573d04 100644 --- a/tests/Moq.Analyzers.Benchmarks/SquiggleCop.Baseline.yaml +++ b/tests/Moq.Analyzers.Benchmarks/SquiggleCop.Baseline.yaml @@ -35,7 +35,7 @@ - {Id: CA1056, Title: URI-like properties should not be strings, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA1058, Title: Types should not extend certain base types, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA1060, Title: Move pinvokes to native methods class, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} -- {Id: CA1061, Title: Do not hide base class methods, Category: Design, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: CA1061, Title: Do not hide base class methods, Category: Design, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: CA1062, Title: Validate arguments of public methods, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA1063, Title: Implement IDisposable Correctly, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA1064, Title: Exceptions should be public, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} @@ -300,6 +300,14 @@ - {Id: CA5405, Title: Do not always skip token validation in delegates, Category: Security, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CS1591, Title: Missing XML comment for publicly visible type or member, Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: false} - {Id: CS8762, Title: Parameter must have a non-null value when exiting in some condition., Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: ECS0100, Title: Prefer implicitly typed local variables, Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: ECS0200, Title: Prefer readonly over const, Category: Maintainability, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: true} +- {Id: ECS0400, Title: Replace string.Format with interpolated string, Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: ECS0500, Title: Prefer FormattableString or string.Create for culture-specific strings, Category: Globalization, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: ECS0600, Title: Avoid stringly-typed APIs, Category: Refactoring, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: ECS0700, Title: Express callbacks with delegates, Category: Design, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: ECS0800, Title: Use the Null Conditional Operator for Event Invocations, Category: Usage, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: ECS0900, Title: Minimize boxing and unboxing, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: true} - {Id: EM0001, Title: Switch on Enum Not Exhaustive, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: EM0002, Title: Switch on Nullable Enum Not Exhaustive, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: EM0003, Title: Switch on Closed Type Not Exhaustive, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} diff --git a/tests/Moq.Analyzers.Test/CompositeAnalyzer.cs b/tests/Moq.Analyzers.Test/CompositeAnalyzer.cs index 56998a73..bed6ddf1 100644 --- a/tests/Moq.Analyzers.Test/CompositeAnalyzer.cs +++ b/tests/Moq.Analyzers.Test/CompositeAnalyzer.cs @@ -17,7 +17,9 @@ public class CompositeAnalyzer : DiagnosticAnalyzer public CompositeAnalyzer() { _analyzers = [.. DiagnosticAnalyzers()]; +#pragma warning disable ECS0900 // Consider using an alternative implementation to avoid boxing and unboxing _supportedDiagnostics = [.. _analyzers.SelectMany(diagnosticAnalyzer => diagnosticAnalyzer.SupportedDiagnostics)]; +#pragma warning restore ECS0900 } /// diff --git a/tests/Moq.Analyzers.Test/SquiggleCop.Baseline.yaml b/tests/Moq.Analyzers.Test/SquiggleCop.Baseline.yaml index 25ac3575..b0e281a2 100644 --- a/tests/Moq.Analyzers.Test/SquiggleCop.Baseline.yaml +++ b/tests/Moq.Analyzers.Test/SquiggleCop.Baseline.yaml @@ -35,7 +35,7 @@ - {Id: CA1056, Title: URI-like properties should not be strings, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA1058, Title: Types should not extend certain base types, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA1060, Title: Move pinvokes to native methods class, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} -- {Id: CA1061, Title: Do not hide base class methods, Category: Design, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: CA1061, Title: Do not hide base class methods, Category: Design, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: CA1062, Title: Validate arguments of public methods, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA1063, Title: Implement IDisposable Correctly, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA1064, Title: Exceptions should be public, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} @@ -299,6 +299,14 @@ - {Id: CA5404, Title: Do not disable token validation checks, Category: Security, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CA5405, Title: Do not always skip token validation in delegates, Category: Security, DefaultSeverity: Warning, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: true} - {Id: CS1591, Title: Missing XML comment for publicly visible type or member, Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: ECS0100, Title: Prefer implicitly typed local variables, Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: ECS0200, Title: Prefer readonly over const, Category: Maintainability, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: ECS0400, Title: Replace string.Format with interpolated string, Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: ECS0500, Title: Prefer FormattableString or string.Create for culture-specific strings, Category: Globalization, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: ECS0600, Title: Avoid stringly-typed APIs, Category: Refactoring, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: ECS0700, Title: Express callbacks with delegates, Category: Design, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: ECS0800, Title: Use the Null Conditional Operator for Event Invocations, Category: Usage, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: ECS0900, Title: Minimize boxing and unboxing, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: true} - {Id: EM0001, Title: Switch on Enum Not Exhaustive, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: EM0002, Title: Switch on Nullable Enum Not Exhaustive, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: EM0003, Title: Switch on Closed Type Not Exhaustive, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false}