diff --git a/build/targets/codeanalysis/CodeAnalysis.props b/build/targets/codeanalysis/CodeAnalysis.props index f25d9b626..040a92c92 100644 --- a/build/targets/codeanalysis/CodeAnalysis.props +++ b/build/targets/codeanalysis/CodeAnalysis.props @@ -26,6 +26,10 @@ all runtime; build; native; contentfiles; analyzers + + all + runtime; build; native; contentfiles; analyzers + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/build/targets/codeanalysis/Packages.props b/build/targets/codeanalysis/Packages.props index 0b6b01952..53a897b36 100644 --- a/build/targets/codeanalysis/Packages.props +++ b/build/targets/codeanalysis/Packages.props @@ -3,6 +3,7 @@ + diff --git a/build/targets/compiler/Compiler.props b/build/targets/compiler/Compiler.props index 7f9eb03a2..307c61826 100644 --- a/build/targets/compiler/Compiler.props +++ b/build/targets/compiler/Compiler.props @@ -6,7 +6,7 @@ - + all runtime; build; native; contentfiles; analyzers diff --git a/build/targets/compiler/Packages.props b/build/targets/compiler/Packages.props index e1375feb1..bc58eca9d 100644 --- a/build/targets/compiler/Packages.props +++ b/build/targets/compiler/Packages.props @@ -1,5 +1,5 @@ - - + + diff --git a/src/Analyzers/AsShouldBeUsedOnlyForInterfaceAnalyzer.cs b/src/Analyzers/AsShouldBeUsedOnlyForInterfaceAnalyzer.cs index 5ec398e9e..990334ff0 100644 --- a/src/Analyzers/AsShouldBeUsedOnlyForInterfaceAnalyzer.cs +++ b/src/Analyzers/AsShouldBeUsedOnlyForInterfaceAnalyzer.cs @@ -34,21 +34,18 @@ public override void Initialize(AnalysisContext context) private static void RegisterCompilationStartAction(CompilationStartAnalysisContext context) { + MoqKnownSymbols knownSymbols = new(context.Compilation); + // Ensure Moq is referenced in the compilation - ImmutableArray mockTypes = context.Compilation.GetMoqMock(); - if (mockTypes.IsEmpty) + if (!knownSymbols.IsMockReferenced()) { return; } // 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(WellKnownMoqNames.AsMethodName)) - .OfType() - .Where(method => method.IsGenericMethod) - .ToImmutableArray(); -#pragma warning restore ECS0900 // Minimize boxing and unboxing + ImmutableArray asMethods = ImmutableArray.CreateRange([ + ..knownSymbols.MockAs, + ..knownSymbols.Mock1As]); if (asMethods.IsEmpty) { diff --git a/src/Analyzers/CallbackSignatureShouldMatchMockedMethodAnalyzer.cs b/src/Analyzers/CallbackSignatureShouldMatchMockedMethodAnalyzer.cs index 21e5f1953..0cc12de9f 100644 --- a/src/Analyzers/CallbackSignatureShouldMatchMockedMethodAnalyzer.cs +++ b/src/Analyzers/CallbackSignatureShouldMatchMockedMethodAnalyzer.cs @@ -31,6 +31,8 @@ public override void Initialize(AnalysisContext context) private static void Analyze(SyntaxNodeAnalysisContext context) { + MoqKnownSymbols knownSymbols = new(context.SemanticModel.Compilation); + InvocationExpressionSyntax callbackOrReturnsInvocation = (InvocationExpressionSyntax)context.Node; SeparatedSyntaxList callbackOrReturnsMethodArguments = callbackOrReturnsInvocation.ArgumentList.Arguments; @@ -49,7 +51,7 @@ private static void Analyze(SyntaxNodeAnalysisContext context) SeparatedSyntaxList lambdaParameters = callbackLambda.ParameterList.Parameters; if (lambdaParameters.Count == 0) return; - InvocationExpressionSyntax? setupInvocation = context.SemanticModel.FindSetupMethodFromCallbackInvocation(callbackOrReturnsInvocation, context.CancellationToken); + InvocationExpressionSyntax? setupInvocation = context.SemanticModel.FindSetupMethodFromCallbackInvocation(knownSymbols, callbackOrReturnsInvocation, context.CancellationToken); InvocationExpressionSyntax? mockedMethodInvocation = setupInvocation.FindMockedMethodInvocationFromSetupMethod(); if (mockedMethodInvocation == null) return; diff --git a/src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs b/src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs index 228ec5f92..ae93b7ede 100644 --- a/src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs +++ b/src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs @@ -68,65 +68,42 @@ public override void Initialize(AnalysisContext context) return null; } - private static bool IsExpressionMockBehavior(SyntaxNodeAnalysisContext context, ExpressionSyntax? expression) + private static bool IsExpressionMockBehavior(SyntaxNodeAnalysisContext context, MoqKnownSymbols knownSymbols, ExpressionSyntax? expression) { - if (expression == null) + if (expression is null) { return false; } - if (expression is MemberAccessExpressionSyntax memberAccessExpressionSyntax) + SymbolInfo symbolInfo = context.SemanticModel.GetSymbolInfo(expression, context.CancellationToken); + + if (symbolInfo.Symbol is null) { - if (memberAccessExpressionSyntax.Expression is IdentifierNameSyntax identifierNameSyntax - && string.Equals(identifierNameSyntax.Identifier.ValueText, WellKnownMoqNames.MockBehaviorTypeName, StringComparison.Ordinal)) - { - return true; - } + return false; } - else if (expression is IdentifierNameSyntax identifierNameSyntax) - { - SymbolInfo symbolInfo = context.SemanticModel.GetSymbolInfo(identifierNameSyntax, context.CancellationToken); - - if (symbolInfo.Symbol == null) - { - return false; - } - ITypeSymbol? typeSymbol = null; - if (symbolInfo.Symbol is IParameterSymbol parameterSymbol) - { - typeSymbol = parameterSymbol.Type; - } - else if (symbolInfo.Symbol is ILocalSymbol localSymbol) - { - typeSymbol = localSymbol.Type; - } - else if (symbolInfo.Symbol is IFieldSymbol fieldSymbol) - { - typeSymbol = fieldSymbol.Type; - } - - if (typeSymbol != null - && string.Equals(typeSymbol.Name, WellKnownMoqNames.MockBehaviorTypeName, StringComparison.Ordinal)) - { - return true; - } + ISymbol targetSymbol = symbolInfo.Symbol; + if (symbolInfo.Symbol is IParameterSymbol parameterSymbol) + { + targetSymbol = parameterSymbol.Type; } - - // Crude fallback to check if the expression is a Moq.MockBehavior enum - if (expression.ToString().StartsWith(WellKnownMoqNames.FullyQualifiedMoqBehaviorTypeName, StringComparison.Ordinal)) + else if (symbolInfo.Symbol is ILocalSymbol localSymbol) { - return true; + targetSymbol = localSymbol.Type; + } + else if (symbolInfo.Symbol is IFieldSymbol fieldSymbol) + { + targetSymbol = fieldSymbol.Type; } - return false; + return targetSymbol.IsInstanceOf(knownSymbols.MockBehavior); } - private static bool IsFirstArgumentMockBehavior(SyntaxNodeAnalysisContext context, ArgumentListSyntax? argumentList) + private static bool IsFirstArgumentMockBehavior(SyntaxNodeAnalysisContext context, MoqKnownSymbols knownSymbols, ArgumentListSyntax? argumentList) { ExpressionSyntax? expression = argumentList?.Arguments[0].Expression; - return IsExpressionMockBehavior(context, expression); + return IsExpressionMockBehavior(context, knownSymbols, expression); } private static void VerifyDelegateMockAttempt( @@ -174,59 +151,38 @@ private static void AnalyzeCompilation(CompilationStartAnalysisContext context) return; } + MoqKnownSymbols knownSymbols = new(context.Compilation); + // We're interested in the few ways to create mocks: // - new Mock() // - Mock.Of() // - MockRepository.Create() // // Ensure Moq is referenced in the compilation - ImmutableArray mockTypes = context.Compilation.GetMoqMock(); - if (mockTypes.IsEmpty) + if (!knownSymbols.IsMockReferenced()) { return; } // These are for classes - context.RegisterSyntaxNodeAction(AnalyzeNewObject, SyntaxKind.ObjectCreationExpression); - context.RegisterSyntaxNodeAction(AnalyzeInstanceCall, SyntaxKind.InvocationExpression); + context.RegisterSyntaxNodeAction(context => AnalyzeNewObject(context, knownSymbols), SyntaxKind.ObjectCreationExpression); + context.RegisterSyntaxNodeAction(context => AnalyzeInstanceCall(context, knownSymbols), SyntaxKind.InvocationExpression); } - private static void AnalyzeInstanceCall(SyntaxNodeAnalysisContext context) + private static void AnalyzeInstanceCall(SyntaxNodeAnalysisContext context, MoqKnownSymbols knownSymbols) { InvocationExpressionSyntax invocationExpressionSyntax = (InvocationExpressionSyntax)context.Node; - if (invocationExpressionSyntax.Expression is not MemberAccessExpressionSyntax memberAccessExpressionSyntax) - { - return; - } - - if (memberAccessExpressionSyntax.Name is not GenericNameSyntax genericNameSyntax) - { - return; - } - - if (genericNameSyntax.Identifier.Value is not string genericNameSyntaxIdentifierValue) - { - return; - } - - if (string.Equals(genericNameSyntaxIdentifierValue, WellKnownMoqNames.CreateMethodName, StringComparison.Ordinal)) - { - AnalyzeInvocation(context, invocationExpressionSyntax, WellKnownMoqNames.MockFactoryTypeName, true, true); - } - else if (string.Equals(genericNameSyntaxIdentifierValue, WellKnownMoqNames.OfMethodName, StringComparison.Ordinal)) - { - AnalyzeInvocation(context, invocationExpressionSyntax, WellKnownMoqNames.MockTypeName, false, true); - } + AnalyzeInvocation(context, knownSymbols, invocationExpressionSyntax); } private static void AnalyzeInvocation( SyntaxNodeAnalysisContext context, - InvocationExpressionSyntax invocationExpressionSyntax, - string expectedClassName, - bool hasReturnedMock, - bool hasMockBehavior) + MoqKnownSymbols knownSymbols, + InvocationExpressionSyntax invocationExpressionSyntax) { + bool hasReturnedMock = true; + bool hasMockBehavior = true; SymbolInfo symbol = context.SemanticModel.GetSymbolInfo(invocationExpressionSyntax, context.CancellationToken); if (symbol.Symbol is not IMethodSymbol method) @@ -234,38 +190,39 @@ private static void AnalyzeInvocation( return; } - if (!string.Equals(method.ContainingType.Name, expectedClassName, StringComparison.Ordinal)) + if (!method.IsInstanceOf(knownSymbols.MockOf) && !method.IsInstanceOf(knownSymbols.MockRepositoryCreate)) { return; } - ITypeSymbol returnType = method.ReturnType; - if (hasReturnedMock) - { - if (returnType is not INamedTypeSymbol { IsGenericType: true } typeSymbol) - { - return; - } - - returnType = typeSymbol.TypeArguments[0]; - } - // We are calling MockRepository.Create or Mock.Of, determine which ArgumentListSyntax? argumentList = null; - if (WellKnownMoqNames.OfMethodName.Equals(method.Name, StringComparison.Ordinal)) + if (method.IsInstanceOf(knownSymbols.MockOf)) { // Mock.Of can specify condition for construction and MockBehavior, but // cannot specify constructor parameters // // The only parameters that can be passed are not relevant for verification // to just strip them + hasReturnedMock = false; } else { argumentList = invocationExpressionSyntax.ArgumentList; } - VerifyMockAttempt(context, returnType, argumentList, hasMockBehavior); + ITypeSymbol returnType = method.ReturnType; + if (hasReturnedMock) + { + if (returnType is not INamedTypeSymbol { IsGenericType: true } typeSymbol) + { + return; + } + + returnType = typeSymbol.TypeArguments[0]; + } + + VerifyMockAttempt(context, knownSymbols, returnType, argumentList, hasMockBehavior); } /// @@ -273,7 +230,8 @@ private static void AnalyzeInvocation( /// match an existing constructor of the mocked class. /// /// The context. - private static void AnalyzeNewObject(SyntaxNodeAnalysisContext context) + /// The used to lookup symbols against Moq types. + private static void AnalyzeNewObject(SyntaxNodeAnalysisContext context, MoqKnownSymbols knownSymbols) { ObjectCreationExpressionSyntax newExpression = (ObjectCreationExpressionSyntax)context.Node; @@ -283,33 +241,24 @@ private static void AnalyzeNewObject(SyntaxNodeAnalysisContext context) return; } - // Quick check - if (!string.Equals( - genericNameSyntax.Identifier.ValueText, - WellKnownMoqNames.MockTypeName, - StringComparison.Ordinal)) - { - return; - } - - // Full check SymbolInfo symbolInfo = context.SemanticModel.GetSymbolInfo(newExpression, context.CancellationToken); - if (symbolInfo.Symbol is not IMethodSymbol mockConstructorMethod - || mockConstructorMethod.MethodKind != MethodKind.Constructor - || !string.Equals(mockConstructorMethod.ContainingType.ConstructedFrom.ContainingSymbol.Name, WellKnownMoqNames.MoqSymbolName, StringComparison.Ordinal)) + if (!symbolInfo + .Symbol? + .IsInstanceOf(knownSymbols.Mock1?.Constructors ?? ImmutableArray.Empty) + ?? false) { return; } - if (mockConstructorMethod.ReceiverType is not INamedTypeSymbol { IsGenericType: true } typeSymbol) + if (symbolInfo.Symbol?.ContainingType is not INamedTypeSymbol { IsGenericType: true } typeSymbol) { return; } ITypeSymbol mockedClass = typeSymbol.TypeArguments[0]; - VerifyMockAttempt(context, mockedClass, newExpression.ArgumentList, true); + VerifyMockAttempt(context, knownSymbols, mockedClass, newExpression.ArgumentList, true); } /// @@ -423,6 +372,7 @@ private static (bool IsEmpty, Location Location) ConstructorIsEmpty( private static void VerifyMockAttempt( SyntaxNodeAnalysisContext context, + MoqKnownSymbols knownSymbols, ITypeSymbol mockedClass, ArgumentListSyntax? argumentList, bool hasMockBehavior) @@ -436,7 +386,7 @@ private static void VerifyMockAttempt( 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)) + if (hasMockBehavior && arguments.Length > 0 && IsFirstArgumentMockBehavior(context, knownSymbols, argumentList)) { // They passed a mock behavior as the first argument; ignore as Moq swallows it arguments = arguments.RemoveAt(0); diff --git a/src/Analyzers/SetExplicitMockBehaviorAnalyzer.cs b/src/Analyzers/SetExplicitMockBehaviorAnalyzer.cs index 5752907c7..567073202 100644 --- a/src/Analyzers/SetExplicitMockBehaviorAnalyzer.cs +++ b/src/Analyzers/SetExplicitMockBehaviorAnalyzer.cs @@ -34,28 +34,28 @@ public override void Initialize(AnalysisContext context) private static void RegisterCompilationStartAction(CompilationStartAnalysisContext context) { + MoqKnownSymbols knownSymbols = new(context.Compilation); + // Ensure Moq is referenced in the compilation - ImmutableArray mockTypes = context.Compilation.GetMoqMock(); - if (mockTypes.IsEmpty) + if (!knownSymbols.IsMockReferenced()) { return; } // Look for the MockBehavior type and provide it to Analyze to avoid looking it up multiple times. - INamedTypeSymbol? mockBehaviorSymbol = context.Compilation.GetTypeByMetadataName(WellKnownMoqNames.FullyQualifiedMoqBehaviorTypeName); + INamedTypeSymbol? mockBehaviorSymbol = knownSymbols.MockBehavior; if (mockBehaviorSymbol is null) { return; } // Look for the Mock.Of() method and provide it to Analyze to avoid looking it up multiple times. -#pragma warning disable ECS0900 // Minimize boxing and unboxing - ImmutableArray ofMethods = mockTypes - .SelectMany(mockType => mockType.GetMembers(WellKnownMoqNames.OfMethodName)) - .OfType() - .Where(method => method.IsGenericMethod) + ImmutableArray ofMethods = knownSymbols.MockOf; + + ImmutableArray mockTypes = + new INamedTypeSymbol?[] { knownSymbols.Mock1, knownSymbols.MockRepository } + .WhereNotNull() .ToImmutableArray(); -#pragma warning restore ECS0900 // Minimize boxing and unboxing context.RegisterOperationAction( context => AnalyzeNewObject(context, mockTypes, mockBehaviorSymbol), diff --git a/src/Analyzers/SetupShouldBeUsedOnlyForOverridableMembersAnalyzer.cs b/src/Analyzers/SetupShouldBeUsedOnlyForOverridableMembersAnalyzer.cs index d4bdd265f..71c11409d 100644 --- a/src/Analyzers/SetupShouldBeUsedOnlyForOverridableMembersAnalyzer.cs +++ b/src/Analyzers/SetupShouldBeUsedOnlyForOverridableMembersAnalyzer.cs @@ -1,5 +1,4 @@ -using System.Runtime.CompilerServices; -using ISymbolExtensions = Microsoft.CodeAnalysis.ISymbolExtensions; +using System.Diagnostics.CodeAnalysis; namespace Moq.Analyzers; @@ -32,12 +31,20 @@ public override void Initialize(AnalysisContext context) context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.InvocationExpression); } + [SuppressMessage("Design", "MA0051:Method is too long", Justification = "Should be fixed. Ignoring for now to avoid additional churn as part of larger refactor.")] private static void Analyze(SyntaxNodeAnalysisContext context) { InvocationExpressionSyntax setupInvocation = (InvocationExpressionSyntax)context.Node; - if (setupInvocation.Expression is not MemberAccessExpressionSyntax memberAccessExpression - || !context.SemanticModel.IsMoqSetupMethod(memberAccessExpression, context.CancellationToken)) + MoqKnownSymbols knownSymbols = new(context.SemanticModel.Compilation); + + if (setupInvocation.Expression is not MemberAccessExpressionSyntax memberAccessExpression) + { + return; + } + + SymbolInfo memberAccessSymbolInfo = context.SemanticModel.GetSymbolInfo(memberAccessExpression, context.CancellationToken); + if (memberAccessSymbolInfo.Symbol is null || !context.SemanticModel.IsMoqSetupMethod(knownSymbols, memberAccessSymbolInfo.Symbol, context.CancellationToken)) { return; } @@ -66,17 +73,12 @@ private static void Analyze(SyntaxNodeAnalysisContext context) { case IPropertySymbol propertySymbol: // Check if the property is Task.Result and skip diagnostic if it is - if (IsTaskResultProperty(propertySymbol, context)) - { - return; - } - - if (propertySymbol.IsOverridable()) + if (IsTaskResultProperty(propertySymbol, knownSymbols)) { return; } - if (propertySymbol.IsMethodReturnTypeTask()) + if (propertySymbol.IsOverridable() || propertySymbol.IsMethodReturnTypeTask()) { return; } @@ -95,7 +97,7 @@ private static void Analyze(SyntaxNodeAnalysisContext context) context.ReportDiagnostic(diagnostic); } - private static bool IsTaskResultProperty(IPropertySymbol propertySymbol, SyntaxNodeAnalysisContext context) + private static bool IsTaskResultProperty(IPropertySymbol propertySymbol, MoqKnownSymbols knownSymbols) { // Check if the property is named "Result" if (!string.Equals(propertySymbol.Name, "Result", StringComparison.Ordinal)) @@ -104,7 +106,7 @@ private static bool IsTaskResultProperty(IPropertySymbol propertySymbol, SyntaxN } // Check if the containing type is Task - INamedTypeSymbol? taskOfTType = context.SemanticModel.Compilation.GetTypeByMetadataName("System.Threading.Tasks.Task`1"); + INamedTypeSymbol? taskOfTType = knownSymbols.Task1; if (taskOfTType == null) { diff --git a/src/Analyzers/SetupShouldNotIncludeAsyncResultAnalyzer.cs b/src/Analyzers/SetupShouldNotIncludeAsyncResultAnalyzer.cs index 057b30c1e..d630941b8 100644 --- a/src/Analyzers/SetupShouldNotIncludeAsyncResultAnalyzer.cs +++ b/src/Analyzers/SetupShouldNotIncludeAsyncResultAnalyzer.cs @@ -40,10 +40,17 @@ private static void Analyze(SyntaxNodeAnalysisContext context) return; } + MoqKnownSymbols knownSymbols = new(context.SemanticModel.Compilation); + InvocationExpressionSyntax setupInvocation = (InvocationExpressionSyntax)context.Node; - if (setupInvocation.Expression is not MemberAccessExpressionSyntax memberAccessExpression || - !context.SemanticModel.IsMoqSetupMethod(memberAccessExpression, context.CancellationToken)) + if (setupInvocation.Expression is not MemberAccessExpressionSyntax memberAccessExpression) + { + return; + } + + SymbolInfo memberAccessSymbolInfo = context.SemanticModel.GetSymbolInfo(memberAccessExpression, context.CancellationToken); + if (memberAccessSymbolInfo.Symbol is null || !context.SemanticModel.IsMoqSetupMethod(knownSymbols, memberAccessSymbolInfo.Symbol, context.CancellationToken)) { return; } diff --git a/src/Analyzers/SquiggleCop.Baseline.yaml b/src/Analyzers/SquiggleCop.Baseline.yaml index ad284559f..54cf4f75c 100644 --- a/src/Analyzers/SquiggleCop.Baseline.yaml +++ b/src/Analyzers/SquiggleCop.Baseline.yaml @@ -307,6 +307,15 @@ - {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: CS0419, Title: Ambiguous reference in cref attribute, Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS0649, Title: 'Field is never assigned to, and will always have its default value', Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1570, Title: XML comment has badly formed XML, Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1572, Title: 'XML comment has a param tag, but there is no parameter by that name', Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1573, Title: Parameter has no matching param tag in the XML comment (but other parameters do), Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1574, Title: XML comment has cref attribute that could not be resolved, Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1734, Title: 'XML comment has a paramref tag, but there is no parameter by that name', Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS8669, Title: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Auto-generated code requires an explicit '#nullable' directive in source., Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS9216, Title: A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement., 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} @@ -330,8 +339,24 @@ - {Id: EM0104, Title: Duplicate Closed Attribute, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: EM0105, Title: Duplicate Case Type, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: EnableGenerateDocumentationFile, Title: Set MSBuild property 'GenerateDocumentationFile' to 'true', Category: Style, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0101, Title: Array allocation for params parameter, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0102, Title: Non-overridden virtual method call on value type, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0201, Title: Implicit string concatenation allocation, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0202, Title: Value type to reference type conversion allocation for string concatenation, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0301, Title: Closure Allocation Source, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0302, Title: Display class allocation to capture closure, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0303, Title: Lambda or anonymous method in a generic method allocates a delegate instance, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0401, Title: Possible allocation of reference type enumerator, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0501, Title: Explicit new array type allocation, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: HAA0502, Title: Explicit new reference type allocation, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: HAA0503, Title: Explicit new anonymous object allocation, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: HAA0506, Title: Let clause induced allocation, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: HAA0601, Title: Value type to reference type conversion causing boxing allocation, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0602, Title: Delegate on struct instance caused a boxing allocation, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0603, Title: Delegate allocation from a method group, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0604, Title: Delegate allocation from a method group, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} - {Id: IDE0004, Title: Remove Unnecessary Cast, Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: true} -- {Id: IDE0005, Title: Using directive is unnecessary., Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: true} +- {Id: IDE0005, Title: Using directive is unnecessary., Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} - {Id: IDE0005_gen, Title: Using directive is unnecessary., Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: true} - {Id: IDE0007, Title: Use implicit type, Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} - {Id: IDE0008, Title: Use explicit type, Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} @@ -603,7 +628,6 @@ - {Id: MA0163, Title: UseShellExecute must be false when redirecting standard input or output, Category: Usage, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: MA0164, Title: Use parentheses to make not pattern clearer, Category: Style, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: MA0165, Title: Make interpolated string, Category: Usage, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: true} -- {Id: POLYSP0003, Title: Unsupported C# language version, Category: Microsoft.CodeAnalysis.CSharp.CSharpParseOptions, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: RCS1001, Title: Add braces (when expression spans over multiple lines), Category: Roslynator, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} - {Id: RCS1002, Title: Remove braces, Category: Roslynator, DefaultSeverity: Note, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: false} - {Id: RCS1002FadeOut, Title: Remove braces, Category: Roslynator, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} @@ -886,7 +910,7 @@ - {Id: RS1032, Title: Define diagnostic message correctly, Category: MicrosoftCodeAnalysisDesign, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: RS1033, Title: Define diagnostic description correctly, Category: MicrosoftCodeAnalysisDesign, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: RS1034, Title: Prefer 'IsKind' for checking syntax kinds, Category: MicrosoftCodeAnalysisPerformance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} -- {Id: RS1035, Title: Do not use APIs banned for analyzers, Category: MicrosoftCodeAnalysisCorrectness, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: RS1035, Title: Do not use APIs banned for analyzers, Category: MicrosoftCodeAnalysisCorrectness, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: true} - {Id: RS1036, Title: Specify analyzer banned API enforcement setting, Category: MicrosoftCodeAnalysisCorrectness, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: RS1037, Title: Add "CompilationEnd" custom tag to compilation end diagnostic descriptor, Category: MicrosoftCodeAnalysisDesign, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: RS1038, Title: Compiler extensions should be implemented in assemblies with compiler-provided references, Category: MicrosoftCodeAnalysisCorrectness, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} @@ -1404,7 +1428,7 @@ - {Id: SA1027, Title: Use tabs correctly, Category: StyleCop.CSharp.SpacingRules, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: SA1028, Title: Code should not contain trailing whitespace, Category: StyleCop.CSharp.SpacingRules, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: SA1100, Title: Do not prefix calls with base unless local implementation exists, Category: StyleCop.CSharp.ReadabilityRules, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} -- {Id: SA1101, Title: Prefix local calls with this, Category: StyleCop.CSharp.ReadabilityRules, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error, Note], IsEverSuppressed: false} +- {Id: SA1101, Title: Prefix local calls with this, Category: StyleCop.CSharp.ReadabilityRules, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error, Note], IsEverSuppressed: true} - {Id: SA1102, Title: Query clause should follow previous clause, Category: StyleCop.CSharp.ReadabilityRules, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: SA1103, Title: Query clauses should be on separate lines or all on one line, Category: StyleCop.CSharp.ReadabilityRules, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: SA1104, Title: Query clause should begin on new line when previous clause spans multiple lines, Category: StyleCop.CSharp.ReadabilityRules, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} @@ -1581,7 +1605,7 @@ - {Id: VSTHRD102, Title: Implement internal logic asynchronously, Category: Usage, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} - {Id: VSTHRD103, Title: Call async methods when in an async method, Category: Usage, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: VSTHRD104, Title: Offer async methods, Category: Usage, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} -- {Id: VSTHRD105, Title: Avoid method overloads that assume TaskScheduler.Current, Category: Usage, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: VSTHRD105, Title: Avoid method overloads that assume TaskScheduler.Current, Category: Usage, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: true} - {Id: VSTHRD106, Title: Use InvokeAsync to raise async events, Category: Usage, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: VSTHRD107, Title: Await Task within using expression, Category: Usage, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: VSTHRD108, Title: Assert thread affinity unconditionally, Category: Usage, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} diff --git a/src/BannedSymbols.txt b/src/BannedSymbols.txt index 9f786f1f4..9e4720b50 100644 --- a/src/BannedSymbols.txt +++ b/src/BannedSymbols.txt @@ -6,3 +6,7 @@ M:Microsoft.CodeAnalysis.Diagnostic.Create(Microsoft.CodeAnalysis.DiagnosticDesc M:Microsoft.CodeAnalysis.Diagnostic.Create(Microsoft.CodeAnalysis.DiagnosticDescriptor,Microsoft.CodeAnalysis.Location,Microsoft.CodeAnalysis.DiagnosticSeverity,System.Collections.Generic.IEnumerable{Microsoft.CodeAnalysis.Location},System.Collections.Immutable.ImmutableDictionary{System.String,System.String},System.Object[]);Use DiagnosticExtensions.CreateDiagnostic;Use DiagnosticExtensions.CreateDiagnostic M:Microsoft.CodeAnalysis.Diagnostic.Create(System.String,System.String,Microsoft.CodeAnalysis.LocalizableString,Microsoft.CodeAnalysis.DiagnosticSeverity,Microsoft.CodeAnalysis.DiagnosticSeverity,System.Boolean,System.Int32,Microsoft.CodeAnalysis.LocalizableString,Microsoft.CodeAnalysis.LocalizableString,System.String,Microsoft.CodeAnalysis.Location,System.Collections.Generic.IEnumerable{Microsoft.CodeAnalysis.Location},System.Collections.Generic.IEnumerable{System.String},System.Collections.Immutable.ImmutableDictionary{System.String,System.String});Use DiagnosticExtensions.CreateDiagnostic M:Microsoft.CodeAnalysis.Diagnostic.Create(System.String,System.String,Microsoft.CodeAnalysis.LocalizableString,Microsoft.CodeAnalysis.DiagnosticSeverity,Microsoft.CodeAnalysis.DiagnosticSeverity,System.Boolean,System.Int32,System.Boolean,Microsoft.CodeAnalysis.LocalizableString,Microsoft.CodeAnalysis.LocalizableString,System.String,Microsoft.CodeAnalysis.Location,System.Collections.Generic.IEnumerable{Microsoft.CodeAnalysis.Location},System.Collections.Generic.IEnumerable{System.String},System.Collections.Immutable.ImmutableDictionary{System.String,System.String});Use DiagnosticExtensions.CreateDiagnostic + +// Prefer KnownSymbols over Compilation.GetTypeByMetadataName +M:Microsoft.CodeAnalysis.Compilation.GetTypeByMetadataName(System.String); Use KnownSymbols +M:Microsoft.CodeAnalysis.Compilation.GetTypesByMetadataName(System.String); Use KnownSymbols diff --git a/src/CodeFixes/CallbackSignatureShouldMatchMockedMethodCodeFix.cs b/src/CodeFixes/CallbackSignatureShouldMatchMockedMethodCodeFix.cs index bf799d8ab..3fe5007e9 100644 --- a/src/CodeFixes/CallbackSignatureShouldMatchMockedMethodCodeFix.cs +++ b/src/CodeFixes/CallbackSignatureShouldMatchMockedMethodCodeFix.cs @@ -52,17 +52,19 @@ private static async Task FixCallbackSignatureAsync(SyntaxNode root, D { SemanticModel? semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - if (semanticModel == null) + if (semanticModel is null) { return document; } + MoqKnownSymbols knownSymbols = new(semanticModel.Compilation); + if (oldParameters?.Parent?.Parent?.Parent?.Parent is not InvocationExpressionSyntax callbackInvocation) { return document; } - InvocationExpressionSyntax? setupMethodInvocation = semanticModel.FindSetupMethodFromCallbackInvocation(callbackInvocation, cancellationToken); + InvocationExpressionSyntax? setupMethodInvocation = semanticModel.FindSetupMethodFromCallbackInvocation(knownSymbols, callbackInvocation, cancellationToken); Debug.Assert(setupMethodInvocation != null, nameof(setupMethodInvocation) + " != null"); IMethodSymbol[] matchingMockedMethods = semanticModel.GetAllMatchingMockedMethodSymbolsFromSetupMethodInvocation(setupMethodInvocation).ToArray(); diff --git a/src/CodeFixes/SquiggleCop.Baseline.yaml b/src/CodeFixes/SquiggleCop.Baseline.yaml index 6c13ce870..e1d8ca6ad 100644 --- a/src/CodeFixes/SquiggleCop.Baseline.yaml +++ b/src/CodeFixes/SquiggleCop.Baseline.yaml @@ -307,6 +307,15 @@ - {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: CS0419, Title: Ambiguous reference in cref attribute, Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS0649, Title: 'Field is never assigned to, and will always have its default value', Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1570, Title: XML comment has badly formed XML, Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1572, Title: 'XML comment has a param tag, but there is no parameter by that name', Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1573, Title: Parameter has no matching param tag in the XML comment (but other parameters do), Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1574, Title: XML comment has cref attribute that could not be resolved, Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1734, Title: 'XML comment has a paramref tag, but there is no parameter by that name', Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS8669, Title: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Auto-generated code requires an explicit '#nullable' directive in source., Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS9216, Title: A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement., 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} @@ -314,7 +323,7 @@ - {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: 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} @@ -330,6 +339,22 @@ - {Id: EM0104, Title: Duplicate Closed Attribute, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: EM0105, Title: Duplicate Case Type, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: EnableGenerateDocumentationFile, Title: Set MSBuild property 'GenerateDocumentationFile' to 'true', Category: Style, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0101, Title: Array allocation for params parameter, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0102, Title: Non-overridden virtual method call on value type, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0201, Title: Implicit string concatenation allocation, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0202, Title: Value type to reference type conversion allocation for string concatenation, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0301, Title: Closure Allocation Source, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0302, Title: Display class allocation to capture closure, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0303, Title: Lambda or anonymous method in a generic method allocates a delegate instance, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0401, Title: Possible allocation of reference type enumerator, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0501, Title: Explicit new array type allocation, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: HAA0502, Title: Explicit new reference type allocation, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: HAA0503, Title: Explicit new anonymous object allocation, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: HAA0506, Title: Let clause induced allocation, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: HAA0601, Title: Value type to reference type conversion causing boxing allocation, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0602, Title: Delegate on struct instance caused a boxing allocation, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0603, Title: Delegate allocation from a method group, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0604, Title: Delegate allocation from a method group, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} - {Id: IDE0004, Title: Remove Unnecessary Cast, Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: true} - {Id: IDE0005, Title: Using directive is unnecessary., Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: true} - {Id: IDE0005_gen, Title: Using directive is unnecessary., Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: true} @@ -488,7 +513,7 @@ - {Id: MA0048, Title: File name must match type name, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: MA0049, Title: Type name should not match containing namespace, Category: Design, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: MA0050, Title: Validate arguments correctly in iterator methods, Category: Design, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} -- {Id: MA0051, Title: Method is too long, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: MA0051, Title: Method is too long, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: true} - {Id: MA0052, Title: Replace constant Enum.ToString with nameof, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} - {Id: MA0053, Title: Make class sealed, Category: Design, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} - {Id: MA0054, Title: Embed the caught exception as innerException, Category: Design, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} @@ -603,7 +628,6 @@ - {Id: MA0163, Title: UseShellExecute must be false when redirecting standard input or output, Category: Usage, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: MA0164, Title: Use parentheses to make not pattern clearer, Category: Style, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: MA0165, Title: Make interpolated string, Category: Usage, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: true} -- {Id: POLYSP0003, Title: Unsupported C# language version, Category: Microsoft.CodeAnalysis.CSharp.CSharpParseOptions, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: RCS1001, Title: Add braces (when expression spans over multiple lines), Category: Roslynator, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} - {Id: RCS1002, Title: Remove braces, Category: Roslynator, DefaultSeverity: Note, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: false} - {Id: RCS1002FadeOut, Title: Remove braces, Category: Roslynator, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} @@ -1404,7 +1428,7 @@ - {Id: SA1027, Title: Use tabs correctly, Category: StyleCop.CSharp.SpacingRules, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: SA1028, Title: Code should not contain trailing whitespace, Category: StyleCop.CSharp.SpacingRules, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: SA1100, Title: Do not prefix calls with base unless local implementation exists, Category: StyleCop.CSharp.ReadabilityRules, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} -- {Id: SA1101, Title: Prefix local calls with this, Category: StyleCop.CSharp.ReadabilityRules, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error, Note], IsEverSuppressed: false} +- {Id: SA1101, Title: Prefix local calls with this, Category: StyleCop.CSharp.ReadabilityRules, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error, Note], IsEverSuppressed: true} - {Id: SA1102, Title: Query clause should follow previous clause, Category: StyleCop.CSharp.ReadabilityRules, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: SA1103, Title: Query clauses should be on separate lines or all on one line, Category: StyleCop.CSharp.ReadabilityRules, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: SA1104, Title: Query clause should begin on new line when previous clause spans multiple lines, Category: StyleCop.CSharp.ReadabilityRules, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} @@ -1581,7 +1605,7 @@ - {Id: VSTHRD102, Title: Implement internal logic asynchronously, Category: Usage, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} - {Id: VSTHRD103, Title: Call async methods when in an async method, Category: Usage, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: VSTHRD104, Title: Offer async methods, Category: Usage, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} -- {Id: VSTHRD105, Title: Avoid method overloads that assume TaskScheduler.Current, Category: Usage, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: VSTHRD105, Title: Avoid method overloads that assume TaskScheduler.Current, Category: Usage, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: true} - {Id: VSTHRD106, Title: Use InvokeAsync to raise async events, Category: Usage, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: VSTHRD107, Title: Await Task within using expression, Category: Usage, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: VSTHRD108, Title: Assert thread affinity unconditionally, Category: Usage, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} diff --git a/src/Common/Caching/BoundedCacheWithFactory.cs b/src/Common/Caching/BoundedCacheWithFactory.cs new file mode 100644 index 000000000..db39f7d3e --- /dev/null +++ b/src/Common/Caching/BoundedCacheWithFactory.cs @@ -0,0 +1,78 @@ +// Forked from https://github.com/dotnet/roslyn-analyzers/blob/5dd0dd5db8fa79932517f153854c0f2c24ac98a3/src/Utilities/Compiler/BoundedCacheWithFactory.cs + +namespace Moq.Analyzers.Common.Caching; + +/// +/// Provides bounded cache for analyzers. +/// Acts as a good alternative to +/// when the cached value has a cyclic reference to the key preventing early garbage collection of entries. +/// +/// The type to use as a cache key. +/// The type to use as the cached value. +internal class BoundedCacheWithFactory + where TKey : class +{ + // Bounded weak reference cache. + // Size 5 is an arbitrarily chosen bound, which can be tuned in future as required. + private readonly List> _weakReferencedEntries = new() + { + new WeakReference(null), + new WeakReference(null), + new WeakReference(null), + new WeakReference(null), + new WeakReference(null), + }; + + public TValue GetOrCreateValue(TKey key, Func valueFactory) + { + lock (_weakReferencedEntries) + { + int indexToSetTarget = -1; + for (int i = 0; i < _weakReferencedEntries.Count; i++) + { + WeakReference weakReferencedEntry = _weakReferencedEntries[i]; + if (!weakReferencedEntry.TryGetTarget(out Entry? cachedEntry) || + cachedEntry == null) + { + if (indexToSetTarget == -1) + { + indexToSetTarget = i; + } + + continue; + } + + if (Equals(cachedEntry.Key, key)) + { + // Move the cache hit item to the end of the list + // so it would be least likely to be evicted on next cache miss. + _weakReferencedEntries.RemoveAt(i); + _weakReferencedEntries.Add(weakReferencedEntry); + return cachedEntry.Value; + } + } + + if (indexToSetTarget == -1) + { + indexToSetTarget = 0; + } + + Entry newEntry = new Entry(key, valueFactory(key)); + _weakReferencedEntries[indexToSetTarget].SetTarget(newEntry); + return newEntry.Value; + } + } + + private sealed class Entry + { + public Entry(TKey key, TValue value) + { + Key = key; + Value = value; + } + + public TKey Key { get; } + + public TValue Value { get; } + } +} diff --git a/src/Common/CompilationExtensions.cs b/src/Common/CompilationExtensions.cs deleted file mode 100644 index ba775b298..000000000 --- a/src/Common/CompilationExtensions.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace Moq.Analyzers.Common; - -internal static class CompilationExtensions -{ - /// - /// An extension method that performs for multiple metadata names. - /// - /// The to inspect. - /// A list of type names to query. - /// if the type can't be found or there was an ambiguity during lookup. - public static ImmutableArray GetTypesByMetadataNames(this Compilation compilation, ReadOnlySpan metadataNames) - { - ImmutableArray.Builder builder = ImmutableArray.CreateBuilder(metadataNames.Length); - - foreach (string metadataName in metadataNames) - { - INamedTypeSymbol? type = compilation.GetTypeByMetadataName(metadataName); - if (type is not null) - { - builder.Add(type); - } - } - - return builder.ToImmutable(); - } - - /// - /// Get the Moq.MockRepository, Moq.Mock and Moq.Mock`1 type symbols (if part of the compilation). - /// - /// The to inspect. - /// - /// s for the Moq.Mock symbols that are part of the compilation. - /// An empty array if none (never ). - /// - public static ImmutableArray GetMoqMock(this Compilation compilation) - { - return compilation.GetTypesByMetadataNames([WellKnownMoqNames.FullyQualifiedMoqMockTypeName, WellKnownMoqNames.FullyQualifiedMoqMock1TypeName, WellKnownMoqNames.FullyQualifiedMoqRepositoryTypeName]); - } -} diff --git a/src/Common/EnumerableExtensions.cs b/src/Common/EnumerableExtensions.cs index b13551681..d02d03509 100644 --- a/src/Common/EnumerableExtensions.cs +++ b/src/Common/EnumerableExtensions.cs @@ -40,4 +40,16 @@ internal static class EnumerableExtensions return item; } + + public static IEnumerable WhereNotNull(this IEnumerable source) + where TSource : class + { + return source.Where(item => item is not null)!; + } + + public static IEnumerable WhereNotNull(this IEnumerable source) + where TSource : struct + { + return source.Where(item => item.HasValue).Select(item => item!.Value); + } } diff --git a/src/Common/GlobalUsings.cs b/src/Common/GlobalUsings.cs index 785ced225..c515e83aa 100644 --- a/src/Common/GlobalUsings.cs +++ b/src/Common/GlobalUsings.cs @@ -4,3 +4,4 @@ global using Microsoft.CodeAnalysis.CSharp.Syntax; global using Microsoft.CodeAnalysis.Diagnostics; global using Moq.Analyzers.Common; +global using Moq.Analyzers.Common.WellKnown; diff --git a/src/Common/ISymbolExtensions.cs b/src/Common/ISymbolExtensions.cs index 10041de45..77bb4e115 100644 --- a/src/Common/ISymbolExtensions.cs +++ b/src/Common/ISymbolExtensions.cs @@ -21,7 +21,7 @@ internal static class ISymbolExtensions /// /// MyType<int>() is an instance of MyType<T>(). /// - public static bool IsInstanceOf(this ISymbol symbol, TSymbol other, SymbolEqualityComparer? symbolEqualityComparer = null) + public static bool IsInstanceOf(this ISymbol? symbol, TSymbol? other, SymbolEqualityComparer? symbolEqualityComparer = null) where TSymbol : class, ISymbol { symbolEqualityComparer ??= SymbolEqualityComparer.Default; @@ -79,4 +79,51 @@ public static bool IsOverridable(this ISymbol symbol) { return !symbol.IsSealed && (symbol.IsVirtual || symbol.IsAbstract || symbol.IsOverride); } + + public static SymbolVisibility GetResultantVisibility(this ISymbol symbol) + { + // Start by assuming it's visible. + SymbolVisibility visibility = SymbolVisibility.Public; + + switch (symbol.Kind) + { + case SymbolKind.Alias: + // Aliases are uber private. They're only visible in the same file that they + // were declared in. + return SymbolVisibility.Private; + + case SymbolKind.Parameter: + // Parameters are only as visible as their containing symbol + return GetResultantVisibility(symbol.ContainingSymbol); + + case SymbolKind.TypeParameter: + // Type Parameters are private. + return SymbolVisibility.Private; + } + + while (symbol != null && symbol.Kind != SymbolKind.Namespace) + { + switch (symbol.DeclaredAccessibility) + { + // If we see anything private, then the symbol is private. + case Accessibility.NotApplicable: + case Accessibility.Private: + return SymbolVisibility.Private; + + // If we see anything internal, then knock it down from public to + // internal. + case Accessibility.Internal: + case Accessibility.ProtectedAndInternal: + visibility = SymbolVisibility.Internal; + break; + + // For anything else (Public, Protected, ProtectedOrInternal), the + // symbol stays at the level we've gotten so far. + } + + symbol = symbol.ContainingSymbol; + } + + return visibility; + } } diff --git a/src/Common/ITypeSymbolExtensions.cs b/src/Common/ITypeSymbolExtensions.cs new file mode 100644 index 000000000..23134f5e2 --- /dev/null +++ b/src/Common/ITypeSymbolExtensions.cs @@ -0,0 +1,22 @@ +namespace Moq.Analyzers.Common; + +internal static class ITypeSymbolExtensions +{ + /// + /// Get the base types of a type, including the type itself. + /// + /// + /// Use this to walk the inheritance chain of a type. + /// + /// The to walk. + /// The type and any inherited types. + public static IEnumerable GetBaseTypesAndThis(this ITypeSymbol type) + { + var current = type; + while (current is not null) + { + yield return current; + current = current.BaseType; + } + } +} diff --git a/src/Common/MoqMethodDescriptorBase.cs b/src/Common/MoqMethodDescriptorBase.cs deleted file mode 100644 index f531b8b71..000000000 --- a/src/Common/MoqMethodDescriptorBase.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace Moq.Analyzers.Common; - -/// -/// A base that provides common functionality for identifying if a given -/// is a specific Moq method. -/// -/// -/// Currently the abstract method -/// is specific to because that's the only type of syntax in use. I expect we'll need -/// to loosen this restriction if we start using other types of syntax. -/// -internal abstract class MoqMethodDescriptorBase -{ - private static readonly string ContainingNamespace = WellKnownMoqNames.MoqNamespace; - private static readonly string ContainingType = WellKnownMoqNames.MockTypeName; - - public abstract bool IsMatch(SemanticModel semanticModel, MemberAccessExpressionSyntax memberAccessSyntax, CancellationToken cancellationToken); - - protected static bool IsFastMatch(MemberAccessExpressionSyntax memberAccessSyntax, ReadOnlySpan methodName) => memberAccessSyntax.Name.Identifier.Text.AsSpan().SequenceEqual(methodName); - - protected static bool IsContainedInMockType(IMethodSymbol methodSymbol) => IsInMoqNamespace(methodSymbol) && IsInMockType(methodSymbol); - - private static bool IsInMoqNamespace(ISymbol symbol) => symbol.ContainingNamespace.Name.AsSpan().SequenceEqual(ContainingNamespace.AsSpan()); - - private static bool IsInMockType(ISymbol symbol) => symbol.ContainingType.Name.AsSpan().SequenceEqual(ContainingType.AsSpan()); -} diff --git a/src/Common/MoqSetupMethodDescriptor.cs b/src/Common/MoqSetupMethodDescriptor.cs deleted file mode 100644 index 28d94826b..000000000 --- a/src/Common/MoqSetupMethodDescriptor.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace Moq.Analyzers.Common; - -/// -/// A class that, given a and a , determines if -/// it is a call to the Moq `Mock.Setup()` method. -/// -internal class MoqSetupMethodDescriptor : MoqMethodDescriptorBase -{ - private static readonly string MethodName = "Setup"; - - public override bool IsMatch(SemanticModel semanticModel, MemberAccessExpressionSyntax memberAccessSyntax, CancellationToken cancellationToken) - { - if (!IsFastMatch(memberAccessSyntax, MethodName.AsSpan())) - { - return false; - } - - ISymbol? symbol = semanticModel.GetSymbolInfo(memberAccessSyntax, cancellationToken).Symbol; - - if (symbol is not IMethodSymbol methodSymbol) - { - return false; - } - - if (!IsContainedInMockType(methodSymbol)) - { - return false; - } - - return methodSymbol.Name.AsSpan().SequenceEqual(MethodName.AsSpan()) && methodSymbol.IsGenericMethod; - } -} diff --git a/src/Common/SemanticModelExtensions.cs b/src/Common/SemanticModelExtensions.cs index fb46aafa6..08620c0b9 100644 --- a/src/Common/SemanticModelExtensions.cs +++ b/src/Common/SemanticModelExtensions.cs @@ -7,9 +7,7 @@ namespace Moq.Analyzers.Common; /// internal static class SemanticModelExtensions { - private static readonly MoqMethodDescriptorBase MoqSetupMethodDescriptor = new MoqSetupMethodDescriptor(); - - internal static InvocationExpressionSyntax? FindSetupMethodFromCallbackInvocation(this SemanticModel semanticModel, ExpressionSyntax expression, CancellationToken cancellationToken) + internal static InvocationExpressionSyntax? FindSetupMethodFromCallbackInvocation(this SemanticModel semanticModel, MoqKnownSymbols knownSymbols, ExpressionSyntax expression, CancellationToken cancellationToken) { InvocationExpressionSyntax? invocation = expression as InvocationExpressionSyntax; if (invocation?.Expression is not MemberAccessExpressionSyntax method) @@ -17,12 +15,18 @@ internal static class SemanticModelExtensions return null; } - if (semanticModel.IsMoqSetupMethod(method, cancellationToken)) + SymbolInfo symbolInfo = semanticModel.GetSymbolInfo(method, cancellationToken); + if (symbolInfo.Symbol is null) + { + return null; + } + + if (semanticModel.IsMoqSetupMethod(knownSymbols, symbolInfo.Symbol, cancellationToken)) { return invocation; } - return semanticModel.FindSetupMethodFromCallbackInvocation(method.Expression, cancellationToken); + return semanticModel.FindSetupMethodFromCallbackInvocation(knownSymbols, method.Expression, cancellationToken); } internal static IEnumerable GetAllMatchingMockedMethodSymbolsFromSetupMethodInvocation(this SemanticModel semanticModel, InvocationExpressionSyntax? setupMethodInvocation) @@ -61,9 +65,9 @@ internal static bool IsCallbackOrReturnInvocation(this SemanticModel semanticMod }; } - internal static bool IsMoqSetupMethod(this SemanticModel semanticModel, MemberAccessExpressionSyntax method, CancellationToken cancellationToken) + internal static bool IsMoqSetupMethod(this SemanticModel semanticModel, MoqKnownSymbols knownSymbols, ISymbol symbol, CancellationToken cancellationToken) { - return MoqSetupMethodDescriptor.IsMatch(semanticModel, method, cancellationToken); + return symbol.IsInstanceOf(knownSymbols.Mock1Setup) && symbol is IMethodSymbol { IsGenericMethod: true }; } private static List GetAllMatchingSymbols(this SemanticModel semanticModel, ExpressionSyntax expression) diff --git a/src/Common/SymbolVisibility.cs b/src/Common/SymbolVisibility.cs new file mode 100644 index 000000000..78f0136c7 --- /dev/null +++ b/src/Common/SymbolVisibility.cs @@ -0,0 +1,24 @@ +namespace Moq.Analyzers.Common; + +internal enum SymbolVisibility +{ + /// + /// Public symbol visibility. + /// + Public = 0, + + /// + /// Internal symbol visibility. + /// + Internal = 1, + + /// + /// Private symbol visibility. + /// + Private = 2, + + /// + /// Internal symbol visibility. + /// + Friend = Internal, +} diff --git a/src/Common/WellKnown/KnownSymbols.cs b/src/Common/WellKnown/KnownSymbols.cs new file mode 100644 index 000000000..cc522bbdd --- /dev/null +++ b/src/Common/WellKnown/KnownSymbols.cs @@ -0,0 +1,44 @@ +namespace Moq.Analyzers.Common.WellKnown; + +/// +/// Main entrypoint to access well-known symbols for the analyzer. +/// This class handles caching to prevent multiple lookups for the same symbol. +/// +/// It returns a type derived from in all cases. Use the +/// when necessary +/// for comparisons with s. +/// +internal class KnownSymbols +{ + public KnownSymbols(WellKnownTypeProvider typeProvider) + { + TypeProvider = typeProvider; + } + + public KnownSymbols(Compilation compilation) + : this(WellKnownTypeProvider.GetOrCreate(compilation)) + { + } + + /// + /// Gets the class System.Threading.Tasks.Task. + /// + public INamedTypeSymbol? Task => TypeProvider.GetOrCreateTypeByMetadataName("System.Threading.Tasks.Task"); + + /// + /// Gets the class System.Threading.Tasks.Task<T>. + /// + public INamedTypeSymbol? Task1 => TypeProvider.GetOrCreateTypeByMetadataName("System.Threading.Tasks.Task`1"); + + /// + /// Gets the class System.Threading.Tasks.ValueTask. + /// + public INamedTypeSymbol? ValueTask => TypeProvider.GetOrCreateTypeByMetadataName("System.Threading.Tasks.ValueTask"); + + /// + /// Gets the class System.Threading.Tasks.ValueTask<T>. + /// + public INamedTypeSymbol? ValueTask1 => TypeProvider.GetOrCreateTypeByMetadataName("System.Threading.Tasks.ValueTask`1"); + + protected WellKnownTypeProvider TypeProvider { get; } +} diff --git a/src/Common/WellKnown/MoqKnownSymbolExtensions.cs b/src/Common/WellKnown/MoqKnownSymbolExtensions.cs new file mode 100644 index 000000000..2472a88cd --- /dev/null +++ b/src/Common/WellKnown/MoqKnownSymbolExtensions.cs @@ -0,0 +1,9 @@ +namespace Moq.Analyzers.Common.WellKnown; + +internal static class MoqKnownSymbolExtensions +{ + public static bool IsMockReferenced(this MoqKnownSymbols mqs) + { + return mqs.Mock is not null || mqs.Mock1 is not null || mqs.MockRepository is not null; + } +} diff --git a/src/Common/WellKnown/MoqKnownSymbols.cs b/src/Common/WellKnown/MoqKnownSymbols.cs new file mode 100644 index 000000000..045ba0f36 --- /dev/null +++ b/src/Common/WellKnown/MoqKnownSymbols.cs @@ -0,0 +1,83 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Moq.Analyzers.Common.WellKnown; + +internal class MoqKnownSymbols : KnownSymbols +{ + public MoqKnownSymbols(WellKnownTypeProvider typeProvider) + : base(typeProvider) + { + } + + public MoqKnownSymbols(Compilation compilation) + : base(compilation) + { + } + + /// + /// Gets the class Moq.Mock. + /// + public INamedTypeSymbol? Mock => TypeProvider.GetOrCreateTypeByMetadataName("Moq.Mock"); + + /// + /// Gets the methods for Moq.Mock.As. + /// + public ImmutableArray MockAs => Mock?.GetMembers("As").OfType().ToImmutableArray() ?? ImmutableArray.Empty; + + /// + /// Gets the methods for Moq.Mock.Of. + /// + public ImmutableArray MockOf => Mock?.GetMembers("Of").OfType().ToImmutableArray() ?? ImmutableArray.Empty; + + /// + /// Gets the class Moq.Mock<T>. + /// + public INamedTypeSymbol? Mock1 => TypeProvider.GetOrCreateTypeByMetadataName("Moq.Mock`1"); + + /// + /// Gets the methods for Moq.Mock<T>.As. + /// + public ImmutableArray Mock1As => Mock1?.GetMembers("As").OfType().ToImmutableArray() ?? ImmutableArray.Empty; + + /// + /// Gets the methods for Moq.Mock<T>.Setup. + /// + public ImmutableArray Mock1Setup => Mock1?.GetMembers("Setup").OfType().ToImmutableArray() ?? ImmutableArray.Empty; + + /// + /// Gets the class Moq.MockRepository. + /// + public INamedTypeSymbol? MockRepository => TypeProvider.GetOrCreateTypeByMetadataName("Moq.MockRepository"); + + /// + /// Gets the methods for Moq.MockRepository.Of. + /// + /// + /// MockRepository is a subclass of MockFactory. + /// However, MockFactory is marked as obsolete. To avoid coupling + /// ourselves to this implementation detail, we walk base types + /// when looking for members. + /// + [SuppressMessage("Performance", "ECS0900:Minimize boxing and unboxing", Justification = "Minor perf issues. Should revisit later.")] + public ImmutableArray MockRepositoryCreate => MockRepository?.GetBaseTypesAndThis().SelectMany(type => type.GetMembers("Create")).OfType().ToImmutableArray() ?? ImmutableArray.Empty; + + /// + /// Gets the enum Moq.MockBehavior. + /// + public INamedTypeSymbol? MockBehavior => TypeProvider.GetOrCreateTypeByMetadataName("Moq.MockBehavior"); + + /// + /// Gets the field Moq.MockBehavior.Strict. + /// + public IFieldSymbol? MockBehaviorStrict => MockBehavior?.GetMembers("Strict").OfType().SingleOrDefault(); + + /// + /// Gets the field Moq.MockBehavior.Loose. + /// + public IFieldSymbol? MockBehaviorLoose => MockBehavior?.GetMembers("Loose").OfType().SingleOrDefault(); + + /// + /// Gets the field Moq.MockBehavior.Default. + /// + public IFieldSymbol? MockBehaviorDefault => MockBehavior?.GetMembers("Default").OfType().SingleOrDefault(); +} diff --git a/src/Common/WellKnown/WellKnownTypeProvider.cs b/src/Common/WellKnown/WellKnownTypeProvider.cs new file mode 100644 index 000000000..32e238765 --- /dev/null +++ b/src/Common/WellKnown/WellKnownTypeProvider.cs @@ -0,0 +1,288 @@ +// Forked from https://github.com/dotnet/roslyn-analyzers/blob/5dd0dd5db8fa79932517f153854c0f2c24ac98a3/src/Utilities/Compiler/WellKnownTypeProvider.cs + +using System.Collections.Concurrent; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using Moq.Analyzers.Common.Caching; +using Roslyn.Utilities; + +namespace Moq.Analyzers.Common.WellKnown; + +/// +/// Provides and caches well known types in a compilation. +/// +internal class WellKnownTypeProvider +{ + private static readonly BoundedCacheWithFactory ProviderCache = new(); + + /// + /// Static cache of full type names (with namespaces) to namespace name parts, + /// so we can query . + /// + /// + /// Example: "System.Collections.Generic.List`1" => [ "System", "Collections", "Generic" ] + /// + /// https://github.com/dotnet/roslyn/blob/9e786147b8cb884af454db081bb747a5bd36a086/src/Compilers/CSharp/Portable/Symbols/AssemblySymbol.cs#L455 + /// suggests the TypeNames collection can be checked to avoid expensive operations. But realizing TypeNames seems to be + /// as memory intensive as unnecessary calls GetTypeByMetadataName() in some cases. So we'll go with namespace names. + /// + private static readonly ConcurrentDictionary> _fullTypeNameToNamespaceNames = + new(StringComparer.Ordinal); + + /// + /// All the referenced assembly symbols. + /// + /// + /// Seems to be less memory intensive than: + /// foreach (Compilation.Assembly.Modules) + /// foreach (Module.ReferencedAssemblySymbols). + /// + private readonly Lazy> _referencedAssemblies; + + /// + /// Mapping of full name to . + /// + private readonly ConcurrentDictionary _fullNameToTypeMap; + + [SuppressMessage("Performance", "ECS0900:Minimize boxing and unboxing", Justification = "Skipping for now. Should revisit.")] + private WellKnownTypeProvider(Compilation compilation) + { + Compilation = compilation; + _fullNameToTypeMap = new ConcurrentDictionary(StringComparer.Ordinal); + _referencedAssemblies = new Lazy>( + () => + { + return Compilation.Assembly.Modules + .SelectMany(m => m.ReferencedAssemblySymbols) + .Distinct(SymbolEqualityComparer.Default) + .ToImmutableArray(); + }, + LazyThreadSafetyMode.ExecutionAndPublication); + } + + /// + /// Gets the associated with this type provider. + /// + public Compilation Compilation { get; } + + /// + /// Get an existing or create a new for the given . + /// + /// The to create the type provider from. + /// A associated with the given . + public static WellKnownTypeProvider GetOrCreate(Compilation compilation) + { + return ProviderCache.GetOrCreateValue(compilation, CreateWellKnownTypeProvider); + + // Local functions + static WellKnownTypeProvider CreateWellKnownTypeProvider(Compilation compilation) => new(compilation); + } + + /// + /// Attempts to get the type by the full type name. + /// + /// Namespace + type name, e.g. "System.Exception". + /// Named type symbol, if any. + /// True if found in the compilation, false otherwise. + [PerformanceSensitive("https://github.com/dotnet/roslyn-analyzers/issues/4893", AllowCaptures = false)] + public bool TryGetOrCreateTypeByMetadataName( + string fullTypeName, + [NotNullWhen(returnValue: true)] out INamedTypeSymbol? namedTypeSymbol) + { + if (_fullNameToTypeMap.TryGetValue(fullTypeName, out namedTypeSymbol)) + { + return namedTypeSymbol is not null; + } + + return TryGetOrCreateTypeByMetadataNameSlow(fullTypeName, out namedTypeSymbol); + } + + /// + /// Gets a type by its full type name. + /// + /// Namespace + type name, e.g. "System.Exception". + /// The if found, null otherwise. + public INamedTypeSymbol? GetOrCreateTypeByMetadataName(string fullTypeName) + { + TryGetOrCreateTypeByMetadataName(fullTypeName, out INamedTypeSymbol? namedTypeSymbol); + return namedTypeSymbol; + } + + private static ImmutableArray GetNamespaceNamesFromFullTypeName(string fullTypeName) + { + ImmutableArray.Builder namespaceNamesBuilder = ImmutableArray.CreateBuilder(); + + int prevStartIndex = 0; + for (int i = 0; i < fullTypeName.Length; i++) + { + if (fullTypeName[i] == '.') + { + namespaceNamesBuilder.Add(fullTypeName[prevStartIndex..i]); + prevStartIndex = i + 1; + } + else if (!IsIdentifierPartCharacter(fullTypeName[i])) + { + break; + } + } + + return namespaceNamesBuilder.ToImmutable(); + } + + /// + /// Returns true if the Unicode character can be a part of an identifier. + /// + /// The Unicode character. + private static bool IsIdentifierPartCharacter(char ch) + { + // identifier-part-character: + // letter-character + // decimal-digit-character + // connecting-character + // combining-character + // formatting-character + + // '\u0061' + if (ch < 'a') + { + // '\u0041' + if (ch < 'A') + { + // '\u0030' and '\u0039' + return ch is >= '0' + and <= '9'; + } + + // '\u005A' or '\u005F' + return ch is <= 'Z' + or '_'; + } + + // '\u007A' + if (ch <= 'z') + { + return true; + } + + // max ASCII + if (ch <= '\u007F') + { + return false; + } + + UnicodeCategory cat = CharUnicodeInfo.GetUnicodeCategory(ch); + + return cat switch + { + // Letter + UnicodeCategory.UppercaseLetter + or UnicodeCategory.LowercaseLetter + or UnicodeCategory.TitlecaseLetter + or UnicodeCategory.ModifierLetter + or UnicodeCategory.OtherLetter + or UnicodeCategory.LetterNumber + or UnicodeCategory.DecimalDigitNumber + or UnicodeCategory.ConnectorPunctuation + or UnicodeCategory.NonSpacingMark + or UnicodeCategory.SpacingCombiningMark + or UnicodeCategory.Format => true, + _ => false, + }; + } + + private static bool IsSubsetOfCollection(ImmutableArray set1, ICollection set2) + { + if (set1.Length > set2.Count) + { + return false; + } + + for (int i = 0; i < set1.Length; i++) + { + if (!set2.Contains(set1[i])) + { + return false; + } + } + + return true; + } + + [SuppressMessage("Design", "MA0051:Method is too long", Justification = "Forked from upstream. Avoiding refactoring to reduce divergence.")] + private bool TryGetOrCreateTypeByMetadataNameSlow( + string fullTypeName, + [NotNullWhen(returnValue: true)] out INamedTypeSymbol? namedTypeSymbol) + { + namedTypeSymbol = _fullNameToTypeMap.GetOrAdd(fullTypeName, ValueFactory, fullTypeName); + + return namedTypeSymbol != null; + + [SuppressMessage("Design", "MA0051:Method is too long", Justification = "Forked from upstream. Avoiding refactoring to reduce divergence.")] + INamedTypeSymbol? ValueFactory(string fullyQualifiedMetadataName, string fullTypeName) + { + // Caching null results is intended. + + // sharwell says: Suppose you reference assembly A with public API X.Y, and you reference assembly B with + // internal API X.Y. Even though you can use X.Y from assembly A, compilation.GetTypeByMetadataName will + // fail outright because it finds two types with the same name. + INamedTypeSymbol? type = null; + + ImmutableArray namespaceNames; + if (string.IsInterned(fullTypeName) != null) + { + namespaceNames = _fullTypeNameToNamespaceNames.GetOrAdd( + fullTypeName, + GetNamespaceNamesFromFullTypeName); + } + else + { + namespaceNames = GetNamespaceNamesFromFullTypeName(fullTypeName); + } + + if (IsSubsetOfCollection(namespaceNames, Compilation.Assembly.NamespaceNames)) + { + type = Compilation.Assembly.GetTypeByMetadataName(fullyQualifiedMetadataName); + } + + if (type is null) + { + Debug.Assert(namespaceNames != null, $"{nameof(namespaceNames)} should not be null"); + + foreach (IAssemblySymbol? referencedAssembly in _referencedAssemblies.Value) + { + if (!IsSubsetOfCollection(namespaceNames, referencedAssembly.NamespaceNames)) + { + continue; + } + + INamedTypeSymbol? currentType = referencedAssembly.GetTypeByMetadataName(fullyQualifiedMetadataName); + if (currentType is null) + { + continue; + } + + switch (currentType.GetResultantVisibility()) + { + case SymbolVisibility.Public: + case SymbolVisibility.Internal when referencedAssembly.GivesAccessTo(Compilation.Assembly): + break; + + default: + continue; + } + + if (type is object) + { + // Multiple visible types with the same metadata name are present. + return null; + } + + type = currentType; + } + } + + return type; + } + } +} diff --git a/src/Common/WellKnownMoqNames.cs b/src/Common/WellKnownMoqNames.cs deleted file mode 100644 index fdedd9387..000000000 --- a/src/Common/WellKnownMoqNames.cs +++ /dev/null @@ -1,74 +0,0 @@ -namespace Moq.Analyzers.Common; - -/// -/// Provides well-known names and fully qualified names for commonly used Moq types, namespaces, and members. -/// -internal static class WellKnownMoqNames -{ - /// - /// Represents the namespace for the Moq library. - /// - internal static readonly string MoqNamespace = "Moq"; - - /// - /// Symbol name for Moq. - /// - internal static readonly string MoqSymbolName = "Moq"; - - /// - /// The name of the 'Moq.Mock' type. - /// - internal static readonly string MockTypeName = "Mock"; - - /// - /// The name of the 'Moq.MockBehavior' type. - /// This type specifies the behavior of the mock (Strict, Loose, etc.). - /// - internal static readonly string MockBehaviorTypeName = "MockBehavior"; - - /// - /// The name of the 'Moq.MockFactory' type. - /// This factory is used for creating multiple mock objects with a shared configuration. - /// - internal static readonly string MockFactoryTypeName = "MockFactory"; - - /// - /// Fully qualified name for the 'Moq.Mock' type. - /// - internal static readonly string FullyQualifiedMoqMockTypeName = $"{MoqNamespace}.{MockTypeName}"; - - /// - /// Fully qualified name for the generic version of 'Moq.Mock{T}'. - /// Represents mocks for specific types. - /// - internal static readonly string FullyQualifiedMoqMock1TypeName = $"{FullyQualifiedMoqMockTypeName}`1"; - - /// - /// Fully qualified name for the 'Moq.MockBehavior' type. - /// - internal static readonly string FullyQualifiedMoqBehaviorTypeName = $"{MoqNamespace}.{MockBehaviorTypeName}"; - - /// - /// Fully qualified name for the 'Moq.MockRepository' type. - /// This type acts as a container for multiple mocks and shared mock configurations. - /// - internal static readonly string FullyQualifiedMoqRepositoryTypeName = $"{MoqNamespace}.MockRepository"; - - /// - /// Represents the method name for the `As` method in Moq. - /// This method is used to cast mocks to interfaces. - /// - internal static readonly string AsMethodName = "As"; - - /// - /// Represents the method name for the `Create` method in Moq. - /// This method is used to create instances of mocks. - /// - internal static readonly string CreateMethodName = "Create"; - - /// - /// Represents the method name for the `Of` method in Moq. - /// This method is used to create a mock from a type without directly specifying the constructor. - /// - internal static readonly string OfMethodName = "Of"; -} diff --git a/tests/Moq.Analyzers.Benchmarks/SquiggleCop.Baseline.yaml b/tests/Moq.Analyzers.Benchmarks/SquiggleCop.Baseline.yaml index 63b90e5bf..43474dfdc 100644 --- a/tests/Moq.Analyzers.Benchmarks/SquiggleCop.Baseline.yaml +++ b/tests/Moq.Analyzers.Benchmarks/SquiggleCop.Baseline.yaml @@ -307,8 +307,15 @@ - {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: CS0419, Title: Ambiguous reference in cref attribute, Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1572, Title: 'XML comment has a param tag, but there is no parameter by that name', Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1573, Title: Parameter has no matching param tag in the XML comment (but other parameters do), Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1574, Title: XML comment has cref attribute that could not be resolved, Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], 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: CS1734, Title: 'XML comment has a paramref tag, but there is no parameter by that name', Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS8669, Title: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Auto-generated code requires an explicit '#nullable' directive in source., Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} - {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: CS9216, Title: A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement., 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} @@ -332,6 +339,22 @@ - {Id: EM0104, Title: Duplicate Closed Attribute, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: EM0105, Title: Duplicate Case Type, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: EnableGenerateDocumentationFile, Title: Set MSBuild property 'GenerateDocumentationFile' to 'true', Category: Style, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0101, Title: Array allocation for params parameter, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0102, Title: Non-overridden virtual method call on value type, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0201, Title: Implicit string concatenation allocation, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0202, Title: Value type to reference type conversion allocation for string concatenation, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0301, Title: Closure Allocation Source, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0302, Title: Display class allocation to capture closure, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0303, Title: Lambda or anonymous method in a generic method allocates a delegate instance, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0401, Title: Possible allocation of reference type enumerator, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0501, Title: Explicit new array type allocation, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: HAA0502, Title: Explicit new reference type allocation, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: HAA0503, Title: Explicit new anonymous object allocation, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: HAA0506, Title: Let clause induced allocation, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: HAA0601, Title: Value type to reference type conversion causing boxing allocation, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0602, Title: Delegate on struct instance caused a boxing allocation, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0603, Title: Delegate allocation from a method group, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0604, Title: Delegate allocation from a method group, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} - {Id: IDE0004, Title: Remove Unnecessary Cast, Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: true} - {Id: IDE0005, Title: Using directive is unnecessary., Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} - {Id: IDE0005_gen, Title: Using directive is unnecessary., Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: true} @@ -604,7 +627,6 @@ - {Id: MA0163, Title: UseShellExecute must be false when redirecting standard input or output, Category: Usage, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: MA0164, Title: Use parentheses to make not pattern clearer, Category: Style, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: MA0165, Title: Make interpolated string, Category: Usage, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: true} -- {Id: POLYSP0003, Title: Unsupported C# language version, Category: Microsoft.CodeAnalysis.CSharp.CSharpParseOptions, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: RCS1001, Title: Add braces (when expression spans over multiple lines), Category: Roslynator, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} - {Id: RCS1002, Title: Remove braces, Category: Roslynator, DefaultSeverity: Note, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: false} - {Id: RCS1002FadeOut, Title: Remove braces, Category: Roslynator, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} diff --git a/tests/Moq.Analyzers.Test.Analyzers/SquiggleCop.Baseline.yaml b/tests/Moq.Analyzers.Test.Analyzers/SquiggleCop.Baseline.yaml index fde960706..4e92a80a9 100644 --- a/tests/Moq.Analyzers.Test.Analyzers/SquiggleCop.Baseline.yaml +++ b/tests/Moq.Analyzers.Test.Analyzers/SquiggleCop.Baseline.yaml @@ -307,6 +307,15 @@ - {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: CS0419, Title: Ambiguous reference in cref attribute, Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS0649, Title: 'Field is never assigned to, and will always have its default value', Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1570, Title: XML comment has badly formed XML, Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1572, Title: 'XML comment has a param tag, but there is no parameter by that name', Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1573, Title: Parameter has no matching param tag in the XML comment (but other parameters do), Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1574, Title: XML comment has cref attribute that could not be resolved, Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1734, Title: 'XML comment has a paramref tag, but there is no parameter by that name', Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS8669, Title: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Auto-generated code requires an explicit '#nullable' directive in source., Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS9216, Title: A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement., 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} @@ -330,6 +339,22 @@ - {Id: EM0104, Title: Duplicate Closed Attribute, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: EM0105, Title: Duplicate Case Type, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: EnableGenerateDocumentationFile, Title: Set MSBuild property 'GenerateDocumentationFile' to 'true', Category: Style, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0101, Title: Array allocation for params parameter, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0102, Title: Non-overridden virtual method call on value type, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0201, Title: Implicit string concatenation allocation, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0202, Title: Value type to reference type conversion allocation for string concatenation, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0301, Title: Closure Allocation Source, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0302, Title: Display class allocation to capture closure, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0303, Title: Lambda or anonymous method in a generic method allocates a delegate instance, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0401, Title: Possible allocation of reference type enumerator, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0501, Title: Explicit new array type allocation, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: HAA0502, Title: Explicit new reference type allocation, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: HAA0503, Title: Explicit new anonymous object allocation, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: HAA0506, Title: Let clause induced allocation, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: HAA0601, Title: Value type to reference type conversion causing boxing allocation, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0602, Title: Delegate on struct instance caused a boxing allocation, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0603, Title: Delegate allocation from a method group, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0604, Title: Delegate allocation from a method group, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} - {Id: IDE0004, Title: Remove Unnecessary Cast, Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: true} - {Id: IDE0005, Title: Using directive is unnecessary., Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} - {Id: IDE0005_gen, Title: Using directive is unnecessary., Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: true} @@ -602,7 +627,6 @@ - {Id: MA0163, Title: UseShellExecute must be false when redirecting standard input or output, Category: Usage, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: MA0164, Title: Use parentheses to make not pattern clearer, Category: Style, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: MA0165, Title: Make interpolated string, Category: Usage, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: true} -- {Id: POLYSP0003, Title: Unsupported C# language version, Category: Microsoft.CodeAnalysis.CSharp.CSharpParseOptions, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: RCS1001, Title: Add braces (when expression spans over multiple lines), Category: Roslynator, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} - {Id: RCS1002, Title: Remove braces, Category: Roslynator, DefaultSeverity: Note, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: false} - {Id: RCS1002FadeOut, Title: Remove braces, Category: Roslynator, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} @@ -885,7 +909,7 @@ - {Id: RS1032, Title: Define diagnostic message correctly, Category: MicrosoftCodeAnalysisDesign, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: RS1033, Title: Define diagnostic description correctly, Category: MicrosoftCodeAnalysisDesign, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: RS1034, Title: Prefer 'IsKind' for checking syntax kinds, Category: MicrosoftCodeAnalysisPerformance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} -- {Id: RS1035, Title: Do not use APIs banned for analyzers, Category: MicrosoftCodeAnalysisCorrectness, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: RS1035, Title: Do not use APIs banned for analyzers, Category: MicrosoftCodeAnalysisCorrectness, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: true} - {Id: RS1036, Title: Specify analyzer banned API enforcement setting, Category: MicrosoftCodeAnalysisCorrectness, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: RS1037, Title: Add "CompilationEnd" custom tag to compilation end diagnostic descriptor, Category: MicrosoftCodeAnalysisDesign, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: RS1038, Title: Compiler extensions should be implemented in assemblies with compiler-provided references, Category: MicrosoftCodeAnalysisCorrectness, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} @@ -1580,7 +1604,7 @@ - {Id: VSTHRD102, Title: Implement internal logic asynchronously, Category: Usage, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} - {Id: VSTHRD103, Title: Call async methods when in an async method, Category: Usage, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: VSTHRD104, Title: Offer async methods, Category: Usage, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} -- {Id: VSTHRD105, Title: Avoid method overloads that assume TaskScheduler.Current, Category: Usage, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: VSTHRD105, Title: Avoid method overloads that assume TaskScheduler.Current, Category: Usage, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: true} - {Id: VSTHRD106, Title: Use InvokeAsync to raise async events, Category: Usage, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: VSTHRD107, Title: Await Task within using expression, Category: Usage, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: VSTHRD108, Title: Assert thread affinity unconditionally, Category: Usage, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} diff --git a/tests/Moq.Analyzers.Test/SquiggleCop.Baseline.yaml b/tests/Moq.Analyzers.Test/SquiggleCop.Baseline.yaml index 3fec38e22..bc706b924 100644 --- a/tests/Moq.Analyzers.Test/SquiggleCop.Baseline.yaml +++ b/tests/Moq.Analyzers.Test/SquiggleCop.Baseline.yaml @@ -307,7 +307,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: CS0419, Title: Ambiguous reference in cref attribute, Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1572, Title: 'XML comment has a param tag, but there is no parameter by that name', Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1573, Title: Parameter has no matching param tag in the XML comment (but other parameters do), Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS1574, Title: XML comment has cref attribute that could not be resolved, Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], 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: CS1734, Title: 'XML comment has a paramref tag, but there is no parameter by that name', Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS8669, Title: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Auto-generated code requires an explicit '#nullable' directive in source., Category: Compiler, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Warning], IsEverSuppressed: true} +- {Id: CS9216, Title: A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement., 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} @@ -331,6 +338,22 @@ - {Id: EM0104, Title: Duplicate Closed Attribute, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: EM0105, Title: Duplicate Case Type, Category: Logic, DefaultSeverity: Error, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: EnableGenerateDocumentationFile, Title: Set MSBuild property 'GenerateDocumentationFile' to 'true', Category: Style, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0101, Title: Array allocation for params parameter, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0102, Title: Non-overridden virtual method call on value type, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0201, Title: Implicit string concatenation allocation, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0202, Title: Value type to reference type conversion allocation for string concatenation, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0301, Title: Closure Allocation Source, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0302, Title: Display class allocation to capture closure, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0303, Title: Lambda or anonymous method in a generic method allocates a delegate instance, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0401, Title: Possible allocation of reference type enumerator, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0501, Title: Explicit new array type allocation, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: HAA0502, Title: Explicit new reference type allocation, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: HAA0503, Title: Explicit new anonymous object allocation, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: HAA0506, Title: Let clause induced allocation, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} +- {Id: HAA0601, Title: Value type to reference type conversion causing boxing allocation, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0602, Title: Delegate on struct instance caused a boxing allocation, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0603, Title: Delegate allocation from a method group, Category: Performance, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} +- {Id: HAA0604, Title: Delegate allocation from a method group, Category: Performance, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} - {Id: IDE0004, Title: Remove Unnecessary Cast, Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: true} - {Id: IDE0005, Title: Using directive is unnecessary., Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} - {Id: IDE0005_gen, Title: Using directive is unnecessary., Category: Style, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: true} @@ -603,7 +626,6 @@ - {Id: MA0163, Title: UseShellExecute must be false when redirecting standard input or output, Category: Usage, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: MA0164, Title: Use parentheses to make not pattern clearer, Category: Style, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: MA0165, Title: Make interpolated string, Category: Usage, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: true} -- {Id: POLYSP0003, Title: Unsupported C# language version, Category: Microsoft.CodeAnalysis.CSharp.CSharpParseOptions, DefaultSeverity: Warning, IsEnabledByDefault: true, EffectiveSeverities: [Error], IsEverSuppressed: false} - {Id: RCS1001, Title: Add braces (when expression spans over multiple lines), Category: Roslynator, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false} - {Id: RCS1002, Title: Remove braces, Category: Roslynator, DefaultSeverity: Note, IsEnabledByDefault: false, EffectiveSeverities: [None], IsEverSuppressed: false} - {Id: RCS1002FadeOut, Title: Remove braces, Category: Roslynator, DefaultSeverity: Note, IsEnabledByDefault: true, EffectiveSeverities: [Note], IsEverSuppressed: false}