Skip to content

Commit

Permalink
Basic implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
zsolt-kolbay-sonarsource committed Dec 11, 2023
1 parent b36349a commit 03eda10
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ internal static class IOperationExtensions
internal static IPropertyReferenceOperationWrapper? AsPropertyReference(this IOperation operation) =>
operation.As(OperationKindEx.PropertyReference, IPropertyReferenceOperationWrapper.FromOperation);

internal static ITupleOperationWrapper? AsTuple(this IOperation operation) =>
operation.As(OperationKindEx.Tuple, ITupleOperationWrapper.FromOperation);

internal static IAwaitOperationWrapper ToAwait(this IOperation operation) =>
IAwaitOperationWrapper.FromOperation(operation);

Expand All @@ -87,6 +90,9 @@ internal static class IOperationExtensions
internal static IConversionOperationWrapper ToConversion(this IOperation operation) =>
IConversionOperationWrapper.FromOperation(operation);

internal static IDeclarationExpressionOperationWrapper ToIDeclarationExpression(this IOperation operation) =>
IDeclarationExpressionOperationWrapper.FromOperation(operation);

internal static IIncrementOrDecrementOperationWrapper ToIncrementOrDecrement(this IOperation operation) =>
IIncrementOrDecrementOperationWrapper.FromOperation(operation);

Expand Down Expand Up @@ -120,6 +126,9 @@ internal static class IOperationExtensions
internal static IEventReferenceOperationWrapper ToEventReference(this IOperation operation) =>
IEventReferenceOperationWrapper.FromOperation(operation);

internal static ITupleOperationWrapper ToTuple(this IOperation operation) =>
ITupleOperationWrapper.FromOperation(operation);

internal static IUnaryOperationWrapper ToUnary(this IOperation operation) =>
IUnaryOperationWrapper.FromOperation(operation);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ internal static class OperationDispatcher
{ OperationKindEx.CompoundAssignment, new CompoundAssignment() },
{ OperationKindEx.Conversion, new Conversion() },
{ OperationKindEx.DeclarationPattern, new DeclarationPattern() },
{ OperationKindEx.DeconstructionAssignment, new DeconstructionAssignment() },
{ OperationKindEx.Decrement, new IncrementOrDecrement() },
{ OperationKindEx.DefaultValue, new DefaultValue() },
{ OperationKindEx.DelegateCreation, new NotNullOperation() },
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* SonarAnalyzer for .NET
* Copyright (C) 2015-2023 SonarSource SA
* mailto: contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

namespace SonarAnalyzer.SymbolicExecution.Roslyn.OperationProcessors;

internal sealed class DeconstructionAssignment : SimpleProcessor<IDeconstructionAssignmentOperationWrapper>
{
protected override IDeconstructionAssignmentOperationWrapper Convert(IOperation operation) =>
IDeconstructionAssignmentOperationWrapper.FromOperation(operation);

protected override ProgramState Process(SymbolicContext context, IDeconstructionAssignmentOperationWrapper assignment)
{
if (assignment.Target.Kind != OperationKindEx.Tuple)
{
return context.State;
}

var targetTuple = assignment.Target.ToTuple();
var newState = context.State;
if (assignment.Value.AsTuple() is { } rightSideTuple)
{
for (var i = 0; i < targetTuple.Elements.Length; i++)
{
var target = targetTuple.Elements[i];
var value = rightSideTuple.Elements[i];

var rightSide = context.State[value];
newState = context.State.SetOperationValue(target, rightSide);
if (target.TrackedSymbol(newState) is { } symbol)
{
newState.SetSymbolValue(symbol, rightSide);
}
}

return newState;
}
else
{
foreach (var tupleMember in targetTuple.Elements)
{
newState = newState.SetOperationValue(tupleMember, SymbolicValue.Empty);
if (tupleMember.TrackedSymbol(newState) is { } symbol)
{
newState = newState.SetSymbolValue(symbol, SymbolicValue.Empty);
}
}

return newState;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3125,7 +3125,7 @@ public void Go()

(memoryStream, str) = GetData();

if (memoryStream != null) // Noncompliant FP: memoryStream was reassigned as a tuple
if (memoryStream != null) // Compliant: memoryStream was reassigned as a tuple
{
// some code
}
Expand All @@ -3143,26 +3143,21 @@ public class Repro_7057
public void WithTuple()
{
string current = null;
string last;
do
(current, _) = SomeTuple();
if (current == null)
{
last = current;
(current, _) = SomeTuple();
Console.WriteLine();
}
while (last == null); // Noncompliant FP
}

public void WithString()
{
string current = null;
string last;

do
current = SomeString();
if (current == null)
{
last = current;
current = SomeString();
Console.WriteLine();
}
while (last == null);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ void TwoWaySwapping()
bool? b1 = null;
bool? b2 = true;
(b1, b2) = (b2, b1);
_ = b1.Value; // Noncompliant, FP: after swapping is non-empty
_ = b1.Value; // Compliant: after swapping is non-empty
_ = b2.Value; // FN: after swapping is empty
}

Expand All @@ -197,9 +197,9 @@ void ThreeWaySwapping()
bool? b2 = true;
bool? b3 = null;
(b1, b2, b3) = (b2, b3, b2);
_ = b1.Value; // Noncompliant, FP: after swapping is non-empty
_ = b1.Value; // Compliant: after swapping is non-empty
_ = b2.Value; // FN: after swapping is empty
_ = b3.Value; // Noncompliant, FP: after swapping is non-empty
_ = b3.Value; // Compliant: after swapping is non-empty
}

void CustomDeconstruction()
Expand Down

0 comments on commit 03eda10

Please sign in to comment.