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
|
dotnet_diagnostic.BHI1005.severity = error
|
||||||
# Do not discard local variables
|
# Do not discard local variables
|
||||||
dotnet_diagnostic.BHI1006.severity = error
|
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
|
# Don't call this.GetType() in sealed type, use typeof operator
|
||||||
dotnet_diagnostic.BHI1100.severity = error
|
dotnet_diagnostic.BHI1100.severity = error
|
||||||
# Don't call this.GetType(), use typeof operator (or replace subtype check with better encapsulation)
|
# 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