// Применяем результат к data и заодно проверяем были ли изменения
 private static void Apply(ControlFlowElementData data, ref bool changesAre,
     IDictionary<IVariableDeclaration, VariableDisposeStatus> resultStatusDictionary,
     OneToSetMap<IVariableDeclaration, InvokedExpressionData> invokedExpressions)
 {
     foreach (var resultStatus in resultStatusDictionary)
     {
         var status = data[resultStatus.Key];
         if (status != resultStatus.Value)
         {
             changesAre = true;
             data[resultStatus.Key] = resultStatus.Value;
         }
     }
     changesAre = changesAre || invokedExpressions.Keys.Except(data.InvokedExpressions.Keys).Any();
         // или вычисляется лениво
     data.InvokedExpressions = invokedExpressions;
 }
 public static bool CheckOnDisposeInvocation(IInvocationExpression invocationExpression,
     ControlFlowElementData data,
     bool isInvocationOnDisposableThis, IVariableDeclaration qualifierDisposableVariableDeclaration)
 {
     if (isInvocationOnDisposableThis)
     {
         if (IsSimpleDisposeInvocation(invocationExpression) || IsCloseInvocation(invocationExpression))
         {
             data.ThisStatus = VariableDisposeStatus.Disposed;
             return true;
         }
     }
     else
     {
         if (qualifierDisposableVariableDeclaration != null &&
             (IsSimpleDisposeInvocation(invocationExpression) || IsCloseInvocation(invocationExpression)))
         {
             data[qualifierDisposableVariableDeclaration] = VariableDisposeStatus.Disposed;
             return true;
         }
     }
     return false;
 }
 // Изменяет входную переменную previousElemsStatusSetsDictionary в соответствии с статусами, точно известными для
 // текущего элемента
 private IDictionary<IVariableDeclaration, VariableDisposeStatus> CombinePreviousAndCurrent(IDictionary<IVariableDeclaration, VariableDisposeStatus> previousElemsStatusSetsDictionary,
         ControlFlowElementData currentElemData)
 {
     var result = new Dictionary<IVariableDeclaration, VariableDisposeStatus>(previousElemsStatusSetsDictionary);
     if (currentElemData == null || !currentElemData.IsVisited())
         return result;
     var currentElementStatus = currentElemData.Status;
     foreach (var status in currentElementStatus)
     {
         VariableDisposeStatus previousStatus;
         var hasValue = previousElemsStatusSetsDictionary.TryGetValue(status.Key, out previousStatus);
         var resultStatus = hasValue ? CombinePreviousAndCurrent(previousStatus, status.Value) : status.Value;
         result[status.Key] = resultStatus;
     }
     return result;
 }
 // Обновляет список вызванных методов для this, если это имеет статус DependsOnInvocation.
 // Иначе удаляет список вызванных методов.
 // Cразу применяет все действия.
 // Возвращает были ли изменения.
 private bool UpdateInvokedExpressionsForThis(ICollection<ControlFlowElementData> previousElems,
     ControlFlowElementData data, VariableDisposeStatus resultStatus)
 {
     if (resultStatus != VariableDisposeStatus.DependsOnInvocation)
     {
         if (data.ThisInvokedExpressions.Any())
         {
             data.ThisInvokedExpressions.Clear();
             return true;
         }
     }
     var result = new HashSet<InvokedExpressionData>(data.ThisInvokedExpressions);
     foreach (var previousElem in previousElems)
     {
         if (previousElem == null || !previousElem.IsVisited())
             continue;
         var previousStatus = previousElem.ThisStatus;
         if (previousStatus == null)
             continue;
         if (previousStatus != VariableDisposeStatus.DependsOnInvocation)
             continue;
         result.AddRange(previousElem.ThisInvokedExpressions);
     }
     var changesAre = result.Except(data.ThisInvokedExpressions).Any(); // или вычисляется лениво
     data.ThisInvokedExpressions = result;
     return changesAre;
 }
 // Добавляет текущий элемент в список его перекрестков, если в него можно перейти из хотя бы одного предыдущего элемента,
 // который еще не посещался.
 // Убирает текущий элемент из списка его перекрестков, если если все его предыдущие элементы посещались.
 // При любом изменении устанавливает changesAre в true.
 // Возвращает, завивисит ли элемент хотя бы от одного перекрестка. Т.е. существует ли путь в текущий элемент, по которому
 // мы еще не успели пройти.
 private bool UpdateCrossroads(ControlFlowElementData data, ICollection<ControlFlowElementData> previousElems,
     ref bool changesAre)
 {
     data.Crossroads = GetPreviousCrossroads(previousElems);
     var isCrossroad = IsCrossroad(previousElems);
     if (isCrossroad)
     {
         if (!data.Crossroads.Contains(data.Id))
         {
             changesAre = true;
             data.Crossroads.Add(data.Id);
         }
     }
     else
     {
         if (data.Crossroads.Contains(data.Id))
         {
             changesAre = true;
             data.Crossroads.Remove(data.Id);
         }
     }
     var hasCrossroads = data.Crossroads.Any();
     return hasCrossroads;
 }
 public static void ProcessUsingStatement([NotNull] IUsingStatement usingStatement, ControlFlowElementData data)
 {
     var expressions = usingStatement.Expressions;
     foreach (var expression in expressions)
     {
         var referenceExpression = expression as IReferenceExpression;
         if (referenceExpression != null)
         {
             ProcessReferenceExpressionInUsingStatement(referenceExpression, data);
             continue;
         }
         var thisExpression = expression as IThisExpression;
         if (thisExpression != null)
         {
             ProcessThisExpressionInUsingStatement(data);
         }
     }
 }
 public static void ProcessThisExpressionInUsingStatement(ControlFlowElementData data)
 {
     if (data.ThisStatus == null)
         return;
     data.ThisStatus = VariableDisposeStatus.Disposed;
 }
 public static void ProcessReferenceExpressionInUsingStatement([NotNull] IReferenceExpression referenceExpression,
     ControlFlowElementData data)
 {
     var declaration = GetVariableDeclarationForReferenceExpression(referenceExpression);
     if (declaration == null)
         return;
     var variableData = data[declaration];
     if (variableData == null)
         return;
     data[declaration] = VariableDisposeStatus.Disposed;
 }