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

Fix S2583 FP: Variable Set in Catch Block #8444

Merged
merged 2 commits into from
Dec 7, 2023
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
zsolt-kolbay-sonarsource marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,20 @@ public ExceptionCandidate(Compilation compilation) =>
public ExceptionState FromOperation(ProgramState state, IOperationWrapperSonar operation) =>
operation.Instance.Kind switch
{
OperationKindEx.ArrayElementReference => FromOperation(IArrayElementReferenceOperationWrapper.FromOperation(operation.Instance)),
OperationKindEx.ArrayElementReference => FromOperation(operation.Instance.ToArrayElementReference()),
OperationKindEx.Conversion => FromConversion(operation),
OperationKindEx.DynamicIndexerAccess => new ExceptionState(typeCatalog.SystemIndexOutOfRangeException),
OperationKindEx.DynamicInvocation => ExceptionState.UnknownException, // This raises is Microsoft.CSharp.RuntimeBinder.RuntimeBinderException that we can't access.
OperationKindEx.DynamicMemberReference => ExceptionState.UnknownException, // This raises is Microsoft.CSharp.RuntimeBinder.RuntimeBinderException that we can't access.
OperationKindEx.DynamicObjectCreation => ExceptionState.UnknownException, // This raises is Microsoft.CSharp.RuntimeBinder.RuntimeBinderException that we can't access.
OperationKindEx.EventReference => FromOperation(state, IMemberReferenceOperationWrapper.FromOperation(operation.Instance)),
OperationKindEx.FieldReference => FromOperation(state, IMemberReferenceOperationWrapper.FromOperation(operation.Instance)),
OperationKindEx.Invocation => FromOperation(IInvocationOperationWrapper.FromOperation(operation.Instance)),
OperationKindEx.MethodReference => FromOperation(state, IMemberReferenceOperationWrapper.FromOperation(operation.Instance)),
OperationKindEx.EventReference => FromOperation(state, operation.Instance.ToMemberReference()),
OperationKindEx.FieldReference => FromOperation(state, operation.Instance.ToMemberReference()),
OperationKindEx.Invocation => FromOperation(operation.Instance.ToInvocation()),
OperationKindEx.MethodReference => FromOperation(state, operation.Instance.ToMemberReference()),
OperationKindEx.ObjectCreation => operation.Instance.Type.DerivesFrom(KnownType.System_Exception) ? null : ExceptionState.UnknownException,
OperationKindEx.PropertyReference => FromOperation(state, IMemberReferenceOperationWrapper.FromOperation(operation.Instance)),
OperationKindEx.PropertyReference => FromOperation(state, operation.Instance.ToMemberReference()),
OperationKindEx.Binary => FromOperation(operation.Instance.ToBinary()),
OperationKindEx.CompoundAssignment => FromOperation(operation.Instance.ToCompoundAssignment()),
_ => null
};

Expand Down Expand Up @@ -80,4 +82,17 @@ private static ExceptionState FromOperation(IInvocationOperationWrapper invocati
|| invocation.IsLockRelease() // Needed by S2222
? null
: ExceptionState.UnknownException;

private ExceptionState FromOperation(IBinaryOperationWrapper binary) =>
IsDivision(binary.OperatorKind)
? new ExceptionState(typeCatalog.SystemDivideByZeroException)
: null;

private ExceptionState FromOperation(ICompoundAssignmentOperationWrapper compoundAssignment) =>
IsDivision(compoundAssignment.OperatorKind)
? new ExceptionState(typeCatalog.SystemDivideByZeroException)
: null;

private static bool IsDivision(BinaryOperatorKind operatorKind) =>
operatorKind is BinaryOperatorKind.Divide or BinaryOperatorKind.Remainder or BinaryOperatorKind.IntegerDivide;
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ internal static IFlowCaptureReferenceOperationWrapper ToFlowCaptureReference(thi
internal static ILocalReferenceOperationWrapper ToLocalReference(this IOperation operation) =>
ILocalReferenceOperationWrapper.FromOperation(operation);

internal static IMemberReferenceOperationWrapper ToMemberReference(this IOperation operation) =>
IMemberReferenceOperationWrapper.FromOperation(operation);

internal static IMethodReferenceOperationWrapper ToMethodReference(this IOperation operation) =>
IMethodReferenceOperationWrapper.FromOperation(operation);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ internal class TypeCatalog
public INamedTypeSymbol SystemNullReferenceException { get; }
public INamedTypeSymbol SystemInvalidCastException { get; }
public INamedTypeSymbol SystemArgumentOutOfRangeException { get; }
public INamedTypeSymbol SystemDivideByZeroException { get; }

public TypeCatalog(Compilation compilation)
{
SystemIndexOutOfRangeException = compilation.GetTypeByMetadataName("System.IndexOutOfRangeException");
SystemNullReferenceException = compilation.GetTypeByMetadataName("System.NullReferenceException");
SystemInvalidCastException = compilation.GetTypeByMetadataName("System.InvalidCastException");
SystemArgumentOutOfRangeException = compilation.GetTypeByMetadataName("System.ArgumentOutOfRangeException");
SystemDivideByZeroException = compilation.GetTypeByMetadataName("System.DivideByZeroException");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -707,4 +707,52 @@ public void ExceptionCandidate_Excluded_DoNotThrow()
validator.ValidateTagOrder("BeforeTry", "InTry", "AfterCatch");
validator.ExitStates.Should().HaveCount(1).And.ContainSingle(x => HasNoException(x));
}

[TestMethod]
public void ExceptionCandidate_DivisionByZero()
{
const string code = """
var tag = "BeforeTry";
try
{
tag = "InTry";
_ = 42 / canBeZero;
}
catch
{
tag = "InCatch";
}
tag = "AfterCatch";

""";
var validator = SETestContext.CreateCS(code, "int canBeZero").Validator;
validator.ValidateContainsOperation(OperationKindEx.Binary);
validator.ValidateTagOrder("BeforeTry", "InTry", "InCatch", "AfterCatch");
validator.TagStates("InCatch").Should().ContainSingle(x => HasExceptionOfType(x, "DivideByZeroException"));
validator.ExitStates.Should().ContainSingle().And.ContainSingle(x => HasNoException(x));
}

[TestMethod]
public void ExceptionCandidate_DivisionByZero_Remainder()
{
const string code = """
var tag = "BeforeTry";
try
{
tag = "InTry";
_ = 42 % canBeZero;
}
catch
{
tag = "InCatch";
}
tag = "AfterCatch";

""";
var validator = SETestContext.CreateCS(code, "int canBeZero").Validator;
validator.ValidateContainsOperation(OperationKindEx.Binary);
validator.ValidateTagOrder("BeforeTry", "InTry", "InCatch", "AfterCatch");
validator.TagStates("InCatch").Should().ContainSingle(x => HasExceptionOfType(x, "DivideByZeroException"));
validator.ExitStates.Should().ContainSingle().And.ContainSingle(x => HasNoException(x));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3407,7 +3407,7 @@ public void Method()
{
success = false;
}
if (success) // Noncompliant FP
if (success) // Compliant
{
Console.WriteLine("Success!");
}
Expand Down