Add Analyzer (currently disabled) for target-typed `new` with `throw`
This commit is contained in:
parent
53fcb93d0e
commit
5fd840e145
|
@ -14,6 +14,8 @@ dotnet_diagnostic.BHI1004.severity = error
|
|||
dotnet_diagnostic.BHI1005.severity = error
|
||||
# Do not discard local variables
|
||||
dotnet_diagnostic.BHI1006.severity = error
|
||||
# Don't use target-typed new for throw expressions
|
||||
dotnet_diagnostic.BHI1007.severity = suggestion
|
||||
# Don't call this.GetType() in sealed type, use typeof operator
|
||||
dotnet_diagnostic.BHI1100.severity = error
|
||||
# Don't call this.GetType(), use typeof operator (or replace subtype check with better encapsulation)
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
namespace BizHawk.Analyzers;
|
||||
|
||||
using System.Collections.Immutable;
|
||||
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.Diagnostics;
|
||||
using Microsoft.CodeAnalysis.Operations;
|
||||
|
||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||
public sealed class NoTargetTypedThrowAnalyzer : DiagnosticAnalyzer
|
||||
{
|
||||
private const string ERR_MSG_IMPLICIT = "Specify `Exception` (or a more precise type) explicitly";
|
||||
|
||||
private static readonly DiagnosticDescriptor DiagNoTargetTypedThrow = new(
|
||||
id: "BHI1007",
|
||||
title: "Don't use target-typed new for throw expressions",
|
||||
messageFormat: "{0}",
|
||||
category: "Usage",
|
||||
defaultSeverity: DiagnosticSeverity.Warning,
|
||||
isEnabledByDefault: true);
|
||||
|
||||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(DiagNoTargetTypedThrow);
|
||||
|
||||
public override void Initialize(AnalysisContext context)
|
||||
{
|
||||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
|
||||
context.EnableConcurrentExecution();
|
||||
context.RegisterOperationAction(
|
||||
oac =>
|
||||
{
|
||||
var exceptionOp = ((IThrowOperation) oac.Operation).Exception;
|
||||
if (exceptionOp is null) return; // re-`throw;`
|
||||
void Fail(string message)
|
||||
=> oac.ReportDiagnostic(Diagnostic.Create(DiagNoTargetTypedThrow, exceptionOp.Syntax.GetLocation(), message));
|
||||
switch (exceptionOp.Kind)
|
||||
{
|
||||
case OperationKind.ObjectCreation:
|
||||
case OperationKind.Invocation:
|
||||
case OperationKind.PropertyReference:
|
||||
case OperationKind.LocalReference:
|
||||
return;
|
||||
case OperationKind.Conversion:
|
||||
if (((IConversionOperation) exceptionOp).Operand.Syntax
|
||||
.IsKind(SyntaxKind.ImplicitObjectCreationExpression))
|
||||
{
|
||||
break;
|
||||
}
|
||||
return;
|
||||
default:
|
||||
Fail($"Argument to throw expression was of an unexpected kind: {exceptionOp.GetType().FullName}");
|
||||
return;
|
||||
}
|
||||
Fail(ERR_MSG_IMPLICIT);
|
||||
},
|
||||
OperationKind.Throw);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
namespace BizHawk.Tests.Analyzers;
|
||||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using Verify = Microsoft.CodeAnalysis.CSharp.Testing.CSharpAnalyzerVerifier<
|
||||
BizHawk.Analyzers.NoTargetTypedThrowAnalyzer,
|
||||
Microsoft.CodeAnalysis.Testing.DefaultVerifier>;
|
||||
|
||||
[TestClass]
|
||||
public sealed class NoTargetTypedThrowAnalyzerTests
|
||||
{
|
||||
[TestMethod]
|
||||
public Task CheckMisuseOfXORAssignment()
|
||||
=> Verify.VerifyAnalyzerAsync("""
|
||||
using System;
|
||||
public static class Cases {
|
||||
// not present: throwing a local, which is apparently necessary in Win32 interop
|
||||
private static void V()
|
||||
=> throw ExceptionHelperProp;
|
||||
private static void W()
|
||||
=> throw ExceptionHelperMethod();
|
||||
private static void X() {
|
||||
try {
|
||||
Z();
|
||||
} catch (Exception) {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
private static void Y()
|
||||
=> throw new Exception();
|
||||
private static void Z()
|
||||
=> throw new NotImplementedException();
|
||||
private static void A()
|
||||
=> throw {|BHI1007:new()|};
|
||||
private static Exception ExceptionHelperMethod()
|
||||
=> new();
|
||||
private static Exception ExceptionHelperProp
|
||||
=> new();
|
||||
}
|
||||
""");
|
||||
}
|
Binary file not shown.
Loading…
Reference in New Issue