// Применяем результат к 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; }