From 28a372ce631fa3ec74183992617a119bf673cc37 Mon Sep 17 00:00:00 2001 From: Collin Alpert Date: Tue, 17 Oct 2023 12:58:44 +0200 Subject: [PATCH 1/2] Do not raise CA1065 when in delegate --- ...NotRaiseExceptionsInUnexpectedLocations.cs | 26 ++++++++++++- ...iseExceptionsInUnexpectedLocationsTests.cs | 39 +++++++++++++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/ApiDesignGuidelines/DoNotRaiseExceptionsInUnexpectedLocations.cs b/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/ApiDesignGuidelines/DoNotRaiseExceptionsInUnexpectedLocations.cs index 36b38ea1c4..1a5690a951 100644 --- a/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/ApiDesignGuidelines/DoNotRaiseExceptionsInUnexpectedLocations.cs +++ b/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/ApiDesignGuidelines/DoNotRaiseExceptionsInUnexpectedLocations.cs @@ -84,7 +84,7 @@ public override void Initialize(AnalysisContext context) // Find out if this given method is one of the interesting categories of methods. // For example, certain Equals methods or certain accessors etc. - MethodCategory methodCategory = methodCategories.FirstOrDefault(l => l.IsMatch(methodSymbol, compilation)); + MethodCategory? methodCategory = methodCategories.FirstOrDefault(l => l.IsMatch(methodSymbol, compilation)); if (methodCategory == null) { return; @@ -94,8 +94,14 @@ public override void Initialize(AnalysisContext context) // Throw statements. operationBlockContext.RegisterOperationAction(operationContext => { + var throwOperation = (IThrowOperation)operationContext.Operation; + if (ThrowOperationOccursInDelegate(throwOperation)) + { + return; + } + // Get ThrowOperation's ExceptionType - if (((IThrowOperation)operationContext.Operation).GetThrownExceptionType() is INamedTypeSymbol thrownExceptionType && thrownExceptionType.DerivesFrom(exceptionType)) + if (throwOperation.GetThrownExceptionType() is INamedTypeSymbol thrownExceptionType && thrownExceptionType.DerivesFrom(exceptionType)) { // If no exceptions are allowed or if the thrown exceptions is not an allowed one.. if (methodCategory.AllowedExceptions.IsEmpty || !methodCategory.AllowedExceptions.Any(n => thrownExceptionType.IsAssignableTo(n, compilation))) @@ -109,6 +115,22 @@ public override void Initialize(AnalysisContext context) }); } + private static bool ThrowOperationOccursInDelegate(IThrowOperation throwOperation) + { + var throwParent = throwOperation.Parent; + while (throwParent is not null) + { + if (throwParent is IDelegateCreationOperation) + { + return true; + } + + throwParent = throwParent.Parent; + } + + return false; + } + /// /// This object describes a class of methods where exception throwing statements should be analyzed. /// diff --git a/src/NetAnalyzers/UnitTests/Microsoft.CodeQuality.Analyzers/ApiDesignGuidelines/DoNotRaiseExceptionsInUnexpectedLocationsTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.CodeQuality.Analyzers/ApiDesignGuidelines/DoNotRaiseExceptionsInUnexpectedLocationsTests.cs index 18fca105b5..4c8d2c9ef3 100644 --- a/src/NetAnalyzers/UnitTests/Microsoft.CodeQuality.Analyzers/ApiDesignGuidelines/DoNotRaiseExceptionsInUnexpectedLocationsTests.cs +++ b/src/NetAnalyzers/UnitTests/Microsoft.CodeQuality.Analyzers/ApiDesignGuidelines/DoNotRaiseExceptionsInUnexpectedLocationsTests.cs @@ -573,6 +573,45 @@ End Class await VerifyVB.VerifyAnalyzerAsync(code, GetBasicNoExceptionsResultAt(6, 9, "Finalize", "Exception")); } + + [Fact, WorkItem(6963, "https://github.com/dotnet/roslyn-analyzers/issues/6963")] + public Task Lambda_NoDiagnostic() + { + const string code = """ + using System; + + public class ShouldNotViolate + { + static readonly Action a; + + static ShouldNotViolate() + { + a = () => throw new DivideByZeroException(); + } + } + """; + + return VerifyCS.VerifyAnalyzerAsync(code); + } + + [Fact, WorkItem(6963, "https://github.com/dotnet/roslyn-analyzers/issues/6963")] + public Task VB_Lambda_NoDiagnostic() + { + const string code = """ + Imports System + + Public Class ShouldNotViolate + Shared ReadOnly a As Action + + Shared Sub New() + a = Sub () Throw New DivideByZeroException() + End Sub + End Class + """; + + return VerifyVB.VerifyAnalyzerAsync(code); + } + #endregion #region Operator tests From 88a1407d8377e56c6a32607fd1131ed6c67325cf Mon Sep 17 00:00:00 2001 From: Collin Alpert Date: Mon, 30 Oct 2023 12:08:22 +0100 Subject: [PATCH 2/2] Apply PR comments --- ...oNotRaiseExceptionsInUnexpectedLocations.cs | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/ApiDesignGuidelines/DoNotRaiseExceptionsInUnexpectedLocations.cs b/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/ApiDesignGuidelines/DoNotRaiseExceptionsInUnexpectedLocations.cs index 1a5690a951..8a52badbb8 100644 --- a/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/ApiDesignGuidelines/DoNotRaiseExceptionsInUnexpectedLocations.cs +++ b/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/ApiDesignGuidelines/DoNotRaiseExceptionsInUnexpectedLocations.cs @@ -95,7 +95,7 @@ public override void Initialize(AnalysisContext context) operationBlockContext.RegisterOperationAction(operationContext => { var throwOperation = (IThrowOperation)operationContext.Operation; - if (ThrowOperationOccursInDelegate(throwOperation)) + if (throwOperation.TryGetContainingAnonymousFunctionOrLocalFunction() is not null) { return; } @@ -115,22 +115,6 @@ public override void Initialize(AnalysisContext context) }); } - private static bool ThrowOperationOccursInDelegate(IThrowOperation throwOperation) - { - var throwParent = throwOperation.Parent; - while (throwParent is not null) - { - if (throwParent is IDelegateCreationOperation) - { - return true; - } - - throwParent = throwParent.Parent; - } - - return false; - } - /// /// This object describes a class of methods where exception throwing statements should be analyzed. ///