Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gh 40 group diagnostics into categories #41

Merged
merged 3 commits into from
Oct 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ Analyzers to detect possible NSubstitute usage problems, such as attempts to set

## Diagnostics

* Non-virtual member setup detected (`NonVirtualSetupSpecification`, `NS001`)
* `Received` used without a following method call. (`UnusedReceived`, `NS002`)
* Non-virtual member setup detected (`NonVirtualSetupSpecification`, `NS1000`)
* `Received` used without a following method call. (`UnusedReceived`, `NS5000`)

## Support

Expand Down
17 changes: 15 additions & 2 deletions src/NSubstitute.Analyzers.Shared/DiagnosticCategories.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
namespace NSubstitute.Analyzers.Shared
{
internal class DiagnosticCategories
internal enum DiagnosticCategory
{
public static readonly string Usage = "NSubstitute.Usage";
[DisplayName("Non virtual substitution")]
NonVirtualSubstitution = 1,

[DisplayName("Substitute creation")]
SubstituteCreation,

[DisplayName("Argument specification")]
ArgumentSpecification,

[DisplayName("Call configuration")]
CallConfiguration,

[DisplayName("Usage")]
Usage
}
}
95 changes: 48 additions & 47 deletions src/NSubstitute.Analyzers.Shared/DiagnosticDescriptors.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Reflection;
using System.Resources;
using Microsoft.CodeAnalysis;
using NSubstitute.Analyzers.Shared.Extensions;

namespace NSubstitute.Analyzers.Shared
{
Expand All @@ -15,161 +16,161 @@ internal class DiagnosticDescriptors<T>
CreateDiagnosticDescriptor(
name: nameof(NonVirtualSetupSpecification),
id: DiagnosticIdentifiers.NonVirtualSetupSpecification,
category: DiagnosticCategories.Usage,
category: DiagnosticCategory.NonVirtualSubstitution.GetDisplayName(),
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor UnusedReceived { get; } =
public static DiagnosticDescriptor NonVirtualReceivedSetupSpecification { get; } =
CreateDiagnosticDescriptor(
name: nameof(UnusedReceived),
id: DiagnosticIdentifiers.UnusedReceived,
category: DiagnosticCategories.Usage,
name: nameof(NonVirtualReceivedSetupSpecification),
id: DiagnosticIdentifiers.NonVirtualReceivedSetupSpecification,
category: DiagnosticCategory.NonVirtualSubstitution.GetDisplayName(),
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor UnusedReceivedForOrdinaryMethod { get; } =
public static DiagnosticDescriptor NonVirtualWhenSetupSpecification { get; } =
CreateDiagnosticDescriptor(
name: nameof(UnusedReceivedForOrdinaryMethod),
id: DiagnosticIdentifiers.UnusedReceived,
category: DiagnosticCategories.Usage,
name: nameof(NonVirtualWhenSetupSpecification),
id: DiagnosticIdentifiers.NonVirtualWhenSetupSpecification,
category: DiagnosticCategory.NonVirtualSubstitution.GetDisplayName(),
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor PartialSubstituteForUnsupportedType { get; } =
CreateDiagnosticDescriptor(
name: nameof(PartialSubstituteForUnsupportedType),
id: DiagnosticIdentifiers.PartialSubstituteForUnsupportedType,
category: DiagnosticCategories.Usage,
category: DiagnosticCategory.SubstituteCreation.GetDisplayName(),
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor SubstituteForWithoutAccessibleConstructor { get; } =
CreateDiagnosticDescriptor(
name: nameof(SubstituteForWithoutAccessibleConstructor),
id: DiagnosticIdentifiers.SubstituteForWithoutAccessibleConstructor,
category: DiagnosticCategories.Usage,
category: DiagnosticCategory.SubstituteCreation.GetDisplayName(),
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor SubstituteForConstructorParametersMismatch { get; } =
CreateDiagnosticDescriptor(
name: nameof(SubstituteForConstructorParametersMismatch),
id: DiagnosticIdentifiers.SubstituteForConstructorParametersMismatch,
category: DiagnosticCategories.Usage,
category: DiagnosticCategory.SubstituteCreation.GetDisplayName(),
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor SubstituteForInternalMember { get; } =
CreateDiagnosticDescriptor(
name: nameof(SubstituteForInternalMember),
id: DiagnosticIdentifiers.SubstituteForInternalMember,
category: DiagnosticCategories.Usage,
category: DiagnosticCategory.SubstituteCreation.GetDisplayName(),
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor SubstituteConstructorMismatch { get; } =
CreateDiagnosticDescriptor(
name: nameof(SubstituteConstructorMismatch),
id: DiagnosticIdentifiers.SubstituteConstructorMismatch,
category: DiagnosticCategories.Usage,
category: DiagnosticCategory.SubstituteCreation.GetDisplayName(),
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor SubstituteMultipleClasses { get; } =
CreateDiagnosticDescriptor(
name: nameof(SubstituteMultipleClasses),
id: DiagnosticIdentifiers.SubstituteMultipleClasses,
category: DiagnosticCategories.Usage,
category: DiagnosticCategory.SubstituteCreation.GetDisplayName(),
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor SubstituteConstructorArgumentsForInterface { get; } =
CreateDiagnosticDescriptor(
name: nameof(SubstituteConstructorArgumentsForInterface),
id: DiagnosticIdentifiers.SubstituteConstructorArgumentsForInterface,
category: DiagnosticCategories.Usage,
category: DiagnosticCategory.SubstituteCreation.GetDisplayName(),
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor SubstituteConstructorArgumentsForDelegate { get; } =
CreateDiagnosticDescriptor(
name: nameof(SubstituteConstructorArgumentsForDelegate),
id: DiagnosticIdentifiers.SubstituteConstructorArgumentsForDelegate,
category: DiagnosticCategories.Usage,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor NonVirtualReceivedSetupSpecification { get; } =
CreateDiagnosticDescriptor(
name: nameof(NonVirtualReceivedSetupSpecification),
id: DiagnosticIdentifiers.NonVirtualReceivedSetupSpecification,
category: DiagnosticCategories.Usage,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor NonVirtualWhenSetupSpecification { get; } =
CreateDiagnosticDescriptor(
name: nameof(NonVirtualWhenSetupSpecification),
id: DiagnosticIdentifiers.NonVirtualWhenSetupSpecification,
category: DiagnosticCategories.Usage,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor ReEntrantSubstituteCall { get; } =
CreateDiagnosticDescriptor(
name: nameof(ReEntrantSubstituteCall),
id: DiagnosticIdentifiers.ReEntrantSubstituteCall,
category: DiagnosticCategories.Usage,
category: DiagnosticCategory.SubstituteCreation.GetDisplayName(),
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor CallInfoArgumentOutOfRange { get; } =
CreateDiagnosticDescriptor(
name: nameof(CallInfoArgumentOutOfRange),
id: DiagnosticIdentifiers.CallInfoArgumentOutOfRange,
category: DiagnosticCategories.Usage,
category: DiagnosticCategory.ArgumentSpecification.GetDisplayName(),
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor CallInfoCouldNotConvertParameterAtPosition { get; } =
CreateDiagnosticDescriptor(
name: nameof(CallInfoCouldNotConvertParameterAtPosition),
id: DiagnosticIdentifiers.CallInfoCouldNotConvertParameterAtPosition,
category: DiagnosticCategories.Usage,
category: DiagnosticCategory.ArgumentSpecification.GetDisplayName(),
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor CallInfoCouldNotFindArgumentToThisCall { get; } =
CreateDiagnosticDescriptor(
name: nameof(CallInfoCouldNotFindArgumentToThisCall),
id: DiagnosticIdentifiers.CallInfoCouldNotFindArgumentToThisCall,
category: DiagnosticCategories.Usage,
category: DiagnosticCategory.ArgumentSpecification.GetDisplayName(),
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor CallInfoMoreThanOneArgumentOfType { get; } =
CreateDiagnosticDescriptor(
name: nameof(CallInfoMoreThanOneArgumentOfType),
id: DiagnosticIdentifiers.CallInfoMoreThanOneArgumentOfType,
category: DiagnosticCategories.Usage,
category: DiagnosticCategory.ArgumentSpecification.GetDisplayName(),
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor CallInfoArgumentSetWithIncompatibleValue { get; } =
CreateDiagnosticDescriptor(
name: nameof(CallInfoArgumentSetWithIncompatibleValue),
id: DiagnosticIdentifiers.CallInfoArgumentSetWithIncompatibleValue,
category: DiagnosticCategories.Usage,
category: DiagnosticCategory.ArgumentSpecification.GetDisplayName(),
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor CallInfoArgumentIsNotOutOrRef { get; } = CreateDiagnosticDescriptor(
name: nameof(CallInfoArgumentIsNotOutOrRef),
id: DiagnosticIdentifiers.CallInfoArgumentIsNotOutOrRef,
category: DiagnosticCategories.Usage,
category: DiagnosticCategory.ArgumentSpecification.GetDisplayName(),
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor ReEntrantSubstituteCall { get; } =
CreateDiagnosticDescriptor(
name: nameof(ReEntrantSubstituteCall),
id: DiagnosticIdentifiers.ReEntrantSubstituteCall,
category: DiagnosticCategory.CallConfiguration.GetDisplayName(),
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor UnusedReceived { get; } =
CreateDiagnosticDescriptor(
name: nameof(UnusedReceived),
id: DiagnosticIdentifiers.UnusedReceived,
category: DiagnosticCategory.Usage.GetDisplayName(),
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static DiagnosticDescriptor UnusedReceivedForOrdinaryMethod { get; } =
CreateDiagnosticDescriptor(
name: nameof(UnusedReceivedForOrdinaryMethod),
id: DiagnosticIdentifiers.UnusedReceived,
category: DiagnosticCategory.Usage.GetDisplayName(),
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

private static DiagnosticDescriptor CreateDiagnosticDescriptor(
string name, string id, string category, DiagnosticSeverity defaultSeverity, bool isEnabledByDefault)
{
Expand Down
42 changes: 23 additions & 19 deletions src/NSubstitute.Analyzers.Shared/DiagnosticIdentifiers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,28 @@
{
internal class DiagnosticIdentifiers
{
public static readonly string NonVirtualSetupSpecification = "NS001";
public static readonly string UnusedReceived = "NS002";
public static readonly string PartialSubstituteForUnsupportedType = "NS003";
public static readonly string SubstituteForWithoutAccessibleConstructor = "NS004";
public static readonly string SubstituteForConstructorParametersMismatch = "NS005";
public static readonly string SubstituteForInternalMember = "NS006";
public static readonly string SubstituteConstructorMismatch = "NS007";
public static readonly string SubstituteMultipleClasses = "NS008";
public static readonly string SubstituteConstructorArgumentsForInterface = "NS009";
public static readonly string SubstituteConstructorArgumentsForDelegate = "NS010";
public static readonly string NonVirtualReceivedSetupSpecification = "NS011";
public static readonly string NonVirtualWhenSetupSpecification = "NS012";
public static readonly string ReEntrantSubstituteCall = "NS013";
public static readonly string CallInfoArgumentOutOfRange = "NS014";
public static readonly string CallInfoCouldNotConvertParameterAtPosition = "NS015";
public static readonly string CallInfoCouldNotFindArgumentToThisCall = "NS016";
public static readonly string CallInfoMoreThanOneArgumentOfType = "NS017";
public static readonly string CallInfoArgumentSetWithIncompatibleValue = "NS018";
public static readonly string CallInfoArgumentIsNotOutOrRef = "NS019";
public const string NonVirtualSetupSpecification = "NS1000";
public const string NonVirtualReceivedSetupSpecification = "NS1001";
public const string NonVirtualWhenSetupSpecification = "NS1002";

public const string PartialSubstituteForUnsupportedType = "NS2000";
public const string SubstituteForWithoutAccessibleConstructor = "NS2001";
public const string SubstituteForConstructorParametersMismatch = "NS2002";
public const string SubstituteForInternalMember = "NS2003";
public const string SubstituteConstructorMismatch = "NS2004";
public const string SubstituteMultipleClasses = "NS2005";
public const string SubstituteConstructorArgumentsForInterface = "NS2006";
public const string SubstituteConstructorArgumentsForDelegate = "NS2007";

public const string CallInfoArgumentOutOfRange = "NS3000";
public const string CallInfoCouldNotConvertParameterAtPosition = "NS3001";
public const string CallInfoCouldNotFindArgumentToThisCall = "NS3002";
public const string CallInfoMoreThanOneArgumentOfType = "NS3003";
public const string CallInfoArgumentSetWithIncompatibleValue = "NS3004";
public const string CallInfoArgumentIsNotOutOrRef = "NS3005";

public const string ReEntrantSubstituteCall = "NS4000";

public const string UnusedReceived = "NS5000";
}
}
15 changes: 15 additions & 0 deletions src/NSubstitute.Analyzers.Shared/DisplayNameAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;

namespace NSubstitute.Analyzers.Shared
{
[AttributeUsage(AttributeTargets.Field)]
internal class DisplayNameAttribute : Attribute
{
public string Name { get; }

public DisplayNameAttribute(string name)
{
Name = name;
}
}
}
14 changes: 14 additions & 0 deletions src/NSubstitute.Analyzers.Shared/Extensions/EnumExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Reflection;

namespace NSubstitute.Analyzers.Shared.Extensions
{
internal static class EnumExtensions
{
public static string GetDisplayName(this Enum @enum)
{
var field = @enum.GetType().GetTypeInfo().GetDeclaredField(@enum.ToString());
return field.GetCustomAttribute<DisplayNameAttribute>().Name;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Microsoft.CodeAnalysis.Diagnostics;
using NSubstitute.Analyzers.CSharp.CodeFixProviders;
using NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers;
using NSubstitute.Analyzers.Shared;
using NSubstitute.Analyzers.Tests.Shared.CodeFixProviders;
using Xunit;

Expand Down Expand Up @@ -33,9 +34,9 @@ public void Test()
}";
await VerifyCodeActions(source, new[]
{
"Suppress NS001 for indexer this[] in nsubstitute.json",
"Suppress NS001 for class Foo in nsubstitute.json",
"Suppress NS001 for namespace MyNamespace in nsubstitute.json"
$"Suppress {DiagnosticIdentifiers.NonVirtualSetupSpecification} for indexer this[] in nsubstitute.json",
$"Suppress {DiagnosticIdentifiers.NonVirtualSetupSpecification} for class Foo in nsubstitute.json",
$"Suppress {DiagnosticIdentifiers.NonVirtualSetupSpecification} for namespace MyNamespace in nsubstitute.json"
});
}

Expand All @@ -62,9 +63,9 @@ public void Test()
}";
await VerifyCodeActions(source, new[]
{
"Suppress NS001 for property Bar in nsubstitute.json",
"Suppress NS001 for class Foo in nsubstitute.json",
"Suppress NS001 for namespace MyNamespace in nsubstitute.json"
$"Suppress {DiagnosticIdentifiers.NonVirtualSetupSpecification} for property Bar in nsubstitute.json",
$"Suppress {DiagnosticIdentifiers.NonVirtualSetupSpecification} for class Foo in nsubstitute.json",
$"Suppress {DiagnosticIdentifiers.NonVirtualSetupSpecification} for namespace MyNamespace in nsubstitute.json"
});
}

Expand Down Expand Up @@ -94,9 +95,9 @@ public void Test()
}";
await VerifyCodeActions(source, new[]
{
"Suppress NS001 for method Bar in nsubstitute.json",
"Suppress NS001 for class Foo in nsubstitute.json",
"Suppress NS001 for namespace MyNamespace in nsubstitute.json"
$"Suppress {DiagnosticIdentifiers.NonVirtualSetupSpecification} for method Bar in nsubstitute.json",
$"Suppress {DiagnosticIdentifiers.NonVirtualSetupSpecification} for class Foo in nsubstitute.json",
$"Suppress {DiagnosticIdentifiers.NonVirtualSetupSpecification} for namespace MyNamespace in nsubstitute.json"
});
}

Expand Down
Loading