protected override void SetValueForParameterPointsToLocationOnEntry(IParameterSymbol parameter, PointsToAbstractValue pointsToAbstractValue)
 {
     if (DisposeOwnershipTransferLikelyTypes.Contains(parameter.Type) ||
         (DisposeOwnershipTransferAtConstructor && parameter.ContainingSymbol.IsConstructor()))
     {
         SetAbstractValue(pointsToAbstractValue, DisposeAbstractValue.NotDisposed);
     }
 }
Esempio n. 2
0
            protected override void PostProcessArgument(IArgumentOperation operation, bool isEscaped)
            {
                base.PostProcessArgument(operation, isEscaped);
                if (isEscaped)
                {
                    PostProcessEscapedArgument();
                }

                return;

                // Local functions.
                void PostProcessEscapedArgument()
                {
                    // Discover if a disposable object is being passed into the creation method for this new disposable object
                    // and if the new disposable object assumes ownership of that passed in disposable object.
                    if (IsDisposeOwnershipTransfer())
                    {
                        var pointsToValue = GetPointsToAbstractValue(operation.Value);
                        HandlePossibleEscapingOperation(operation, pointsToValue.Locations);
                    }
                }

                bool IsDisposeOwnershipTransfer()
                {
                    if (!operation.Parameter.Type.IsDisposable(WellKnownTypeProvider.IDisposable))
                    {
                        return(false);
                    }

                    switch (operation.Parent)
                    {
                    case IObjectCreationOperation _:
                        return(DisposeOwnershipTransferAtConstructor ||
                               DisposeOwnershipTransferLikelyTypes.Contains(operation.Parameter.Type));

                    case IInvocationOperation invocation:
                        return(IsDisposableCreationSpecialCase(invocation.TargetMethod) &&
                               DisposeOwnershipTransferLikelyTypes.Contains(operation.Parameter.Type));

                    default:
                        return(false);
                    }
                }
            }
            protected override void PostProcessArgument(IArgumentOperation operation, bool isEscaped)
            {
                base.PostProcessArgument(operation, isEscaped);
                if (isEscaped)
                {
                    // Discover if a disposable object is being passed into the creation method for this new disposable object
                    // and if the new disposable object assumes ownership of that passed in disposable object.
                    if (IsDisposeOwnershipTransfer())
                    {
                        var pointsToValue = GetPointsToAbstractValue(operation.Value);
                        HandlePossibleEscapingOperation(operation, pointsToValue.Locations);
                        return;
                    }
                    else if (FlowBranchConditionKind == ControlFlowConditionKind.WhenFalse &&
                             operation.Parameter.RefKind == RefKind.Out &&
                             operation.Parent is IInvocationOperation invocation &&
                             invocation.TargetMethod.ReturnType.SpecialType == SpecialType.System_Boolean)
                    {
                        // Case 1:
                        //      // Assume 'obj' is not a valid object on the 'else' path.
                        //      if (TryXXX(out IDisposable obj))
                        //      {
                        //          obj.Dispose();
                        //      }
                        //
                        //      return;

                        // Case 2:
                        //      if (!TryXXX(out IDisposable obj))
                        //      {
                        //          return; // Assume 'obj' is not a valid object on this path.
                        //      }
                        //
                        //      obj.Dispose();

                        HandlePossibleInvalidatingOperation(operation);
                        return;
                    }
                }

                // Ref or out argument values from callee might be escaped by assigning to field.
                if (operation.Parameter.RefKind == RefKind.Out || operation.Parameter.RefKind == RefKind.Ref)
                {
                    HandlePossibleEscapingOperation(operation, GetEscapedLocations(operation));
                }

                return;

                // Local functions.
                bool IsDisposeOwnershipTransfer()
                {
                    if (operation.Parameter.RefKind == RefKind.Out)
                    {
                        // Out arguments are always owned by the caller.
                        return(false);
                    }

                    return(operation.Parent switch
                    {
                        IObjectCreationOperation _ => DisposeOwnershipTransferAtConstructor ||
                        DisposeOwnershipTransferLikelyTypes.Contains(operation.Parameter.Type),

                        IInvocationOperation invocation => DisposeOwnershipTransferAtMethodCall ||
                        IsDisposableCreationSpecialCase(invocation.TargetMethod) && DisposeOwnershipTransferLikelyTypes.Contains(operation.Parameter.Type),

                        _ => false,
                    });
                }
            protected override void PostProcessArgument(IArgumentOperation operation, bool isEscaped)
            {
                base.PostProcessArgument(operation, isEscaped);
                if (isEscaped)
                {
                    // Discover if a disposable object is being passed into the creation method for this new disposable object
                    // and if the new disposable object assumes ownership of that passed in disposable object.
                    if (IsDisposeOwnershipTransfer())
                    {
                        var pointsToValue = GetPointsToAbstractValue(operation.Value);
                        HandlePossibleEscapingOperation(operation, pointsToValue.Locations);
                    }
                    else if (FlowBranchConditionKind == ControlFlowConditionKind.WhenFalse &&
                             operation.Parameter.RefKind == RefKind.Out &&
                             operation.Parent is IInvocationOperation invocation &&
                             invocation.TargetMethod.ReturnType.SpecialType == SpecialType.System_Boolean)
                    {
                        // Case 1:
                        //      // Assume 'obj' is not a valid object on the 'else' path.
                        //      if (TryXXX(out IDisposable obj))
                        //      {
                        //          obj.Dispose();
                        //      }
                        //
                        //      return;

                        // Case 2:
                        //      if (!TryXXX(out IDisposable obj))
                        //      {
                        //          return; // Assume 'obj' is not a valid object on this path.
                        //      }
                        //
                        //      obj.Dispose();

                        HandlePossibleInvalidatingOperation(operation);
                    }
                }
                else if (operation.Parameter.RefKind == RefKind.Out || operation.Parameter.RefKind == RefKind.Ref)
                {
                    HandlePossibleEscapingOperation(operation, GetEscapedLocations(operation));
                }

                return;

                // Local functions.
                bool IsDisposeOwnershipTransfer()
                {
                    if (!operation.Parameter.Type.IsDisposable(WellKnownTypeProvider.IDisposable))
                    {
                        return(false);
                    }

                    switch (operation.Parent)
                    {
                    case IObjectCreationOperation _:
                        return(DisposeOwnershipTransferAtConstructor ||
                               DisposeOwnershipTransferLikelyTypes.Contains(operation.Parameter.Type));

                    case IInvocationOperation invocation:
                        return(IsDisposableCreationSpecialCase(invocation.TargetMethod) &&
                               DisposeOwnershipTransferLikelyTypes.Contains(operation.Parameter.Type));

                    default:
                        return(false);
                    }
                }
            }