public Branch FindBranch(SyntaxNode expression, out Condition inlineCondition) { using (new OperationTimer(i => Timings.Update(TimingOperation.FindBranch, i))) { return(InnerFindBranch(this, expression, out inlineCondition)); } }
public MethodFlowAnalysis Analyze(BlockSyntax body, IEnumerable <SyntaxNode> statements) { hasConstraints = false; assignments.Clear(); lambdas.Clear(); using (new OperationTimer(i => Timings.Update(TimingOperation.MethodAnlyzer, i))) { var tree = BuildTree(null, null, statements, false); var lambdaTrees = new List <Branch>(); while (lambdas.Count > 0) { var lambda = lambdas.Dequeue(); if (lambda.Item2.Body is BlockSyntax block) { lambdaTrees.Add(BuildTree(lambda.Item1, null, lambda.Item2.Body.ChildNodes(), true)); } else { lambdaTrees.Add(BuildTree(lambda.Item1, null, new[] { lambda.Item2.Body }, true)); } } // This is kinda a hack. The idea is that we probably wanna search the inner most lambda first. // But since each lambda contains all the statements of the inner lambdas, we'd match on the outer one first. // So reverse the list and start at the bottom. lambdaTrees.Reverse(); var nullAssignments = assignments .Where(i => i.Value != ValueType.NotNull) .Select(i => i.Symbol) .ToList(); if (body != null) { var data = model.AnalyzeDataFlow(body); var variablesThatAreAlwaysNotNull = data.AlwaysAssigned.RemoveAll(i => i is IParameterSymbol || nullAssignments.Any(j => j.Equals(i))); var safeParameters = data.WrittenOutside.Where(i => i.HasNotNullOrCheckNull()); return(new MethodFlowAnalysis( mode, model, assignments, variablesThatAreAlwaysNotNull.AddRange(safeParameters), tree, lambdaTrees, hasConstraints, returnStatements)); } return(new MethodFlowAnalysis( mode, model, assignments, ImmutableArray.Create <ISymbol>(), tree, lambdaTrees, hasConstraints, returnStatements)); } }
public Condition Parse(ConditionType kind, ExpressionSyntax expression) { using (new OperationTimer(i => Timings.Update(TimingOperation.ExpressionToCondition, i))) { var list = new LinkedList <BooleanExpression>(); list.AddFirst(new BooleanExpression(expression)); Queue <LinkedListNode <BooleanExpression> > queue = new Queue <LinkedListNode <BooleanExpression> >(); ExplodeExpression(list, list.First, queue); while (queue.Count > 0) { ExplodeExpression(list, queue.Dequeue(), queue); } var condition = new Condition(kind); var lastOp = Operator.None; foreach (var item in list) { LogicalType conditionType; switch (lastOp) { case Operator.Or: conditionType = LogicalType.Or; break; case Operator.And: conditionType = LogicalType.And; break; default: conditionType = LogicalType.Mixed; break; } if (item.IsIsExpression) { condition = condition.WithIs(conditionType, new ExpressionKey(item.Expression, item.IsType), item.Expression, item.HasNotPrefix); } else { condition = condition.With(conditionType, new ExpressionKey(item.Expression, model), item.Expression, item.Value); } lastOp = item.Operator; } return(condition); } }
public ExpressionStatus IsAlwaysAssigned(SyntaxNode expression, SyntaxNode parent, bool searchAssignments = true) { using (new OperationTimer(i => Timings.Update(TimingOperation.IsAlwaysAssigned, i))) { var argSymbol = model.GetSymbolInfo(expression).Symbol; if (AlwaysAssignedToNotNull.Contains(argSymbol)) { // Agument might have been null, but it was assigned to a NotNull in all execution paths return(ExpressionStatus.Assigned); } var assignmentsForExpression = assignments.Where(i => i.Symbol.Equals(argSymbol)).ToList(); // Fields/properties might be unassigned. We can really only look at locals if (argSymbol is ILocalSymbol) { if (assignmentsForExpression.Count > 0) { if (assignmentsForExpression.All(i => i.Value == ValueType.NotNull)) { return(ExpressionStatus.Assigned); } } } // TODO: cache this? var path = GetListOfParents(parent, out var inlineCondition); var key = new ExpressionKey(expression, model); if (inlineCondition != null && inlineCondition.IsNotNullShortCircuit(key)) { // Short circuiting expression return(ExpressionStatus.Assigned); } // Find the condition that checks for NotNull Branch branchWithNullCheck = GetBranchWithNullCheck(path, key, out var unneededConstraint); if (branchWithNullCheck == null) { if (searchAssignments && argSymbol is ILocalSymbol) { var questionableAssignments = assignmentsForExpression.Where(i => i.Value != ValueType.NotNull).ToList(); if (questionableAssignments.Count > 0) { if (questionableAssignments.Any(i => !IsAlwaysAssigned(i.Expression, parent, false).IsAssigned())) { return(ExpressionStatus.NotAssigned); } return(ExpressionStatus.Assigned); } } return(ExpressionStatus.NotAssigned); } if (NullAssignmentsAreInPath(expression, assignmentsForExpression, branchWithNullCheck)) { return(ExpressionStatus.ReassignedAfterCondition); } return(unneededConstraint ? ExpressionStatus.AssignedWithUnneededConstraint : ExpressionStatus.Assigned); } }
public void Update() { // DO WORK Timings.Update(); }