private static bool IsPotentiallyCachedOrInjectedCore(ExpressionSyntax value, SemanticModel semanticModel, CancellationToken cancellationToken) { var symbol = semanticModel.GetSymbolSafe(value, cancellationToken); if (IsInjectedCore(symbol) == Result.Yes) { return(true); } if (symbol is IPropertySymbol property && !property.IsAutoProperty(cancellationToken)) { using (var returnValues = ReturnValueWalker.Create(value, Search.TopLevel, semanticModel, cancellationToken)) { using (var recursive = RecursiveValues.Create(returnValues.Item, semanticModel, cancellationToken)) { return(IsInjectedCore(recursive, semanticModel, cancellationToken) .IsEither(Result.Yes, Result.Maybe)); } } } using (var sources = AssignedValueWalker.Create(value, semanticModel, cancellationToken)) { using (var recursive = RecursiveValues.Create(sources.Item, semanticModel, cancellationToken)) { return(IsInjectedCore(recursive, semanticModel, cancellationToken).IsEither(Result.Yes, Result.Maybe)); } } }
internal static Result IsAssignedWithCreated(ISymbol symbol, SyntaxNode context, SemanticModel semanticModel, CancellationToken cancellationToken) { using (var pooled = AssignedValueWalker.Create(symbol, context, semanticModel, cancellationToken)) { using (var recursive = RecursiveValues.Create(pooled.Item, semanticModel, cancellationToken)) { return(IsAssignedWithCreated(recursive, semanticModel, cancellationToken)); } } }
internal static Result IsAssignedWithCreated(IFieldSymbol field, SemanticModel semanticModel, CancellationToken cancellationToken) { if (!IsPotentiallyAssignableTo(field?.Type)) { return(Result.No); } using (var pooled = AssignedValueWalker.Create(field, semanticModel, cancellationToken)) { using (var recursive = RecursiveValues.Create(pooled.Item, semanticModel, cancellationToken)) { return(IsAssignedWithCreated(recursive, semanticModel, cancellationToken)); } } }
internal static bool IsAssignedWithCreatedAndNotCachedOrInjected(IFieldSymbol field, SemanticModel semanticModel, CancellationToken cancellationToken) { if (field == null || !IsPotentiallyAssignableTo(field.Type)) { return(false); } using (var sources = AssignedValueWalker.Create(field, semanticModel, cancellationToken)) { using (var recursive = RecursiveValues.Create(sources.Item, semanticModel, cancellationToken)) { return(IsAssignedWithCreated(recursive, semanticModel, cancellationToken).IsEither(Result.Yes, Result.Maybe) && !IsInjectedCore(recursive, semanticModel, cancellationToken).IsEither(Result.Yes, Result.Maybe)); } } }
internal static bool IsAssignedWithCreatedAndInjected(IPropertySymbol property, SemanticModel semanticModel, CancellationToken cancellationToken) { if (property == null || !IsPotentiallyAssignableTo(property.Type)) { return(false); } using (var sources = AssignedValueWalker.Create(property, semanticModel, cancellationToken)) { using (var recursive = RecursiveValues.Create(sources.Item, semanticModel, cancellationToken)) { return(IsAssignedWithCreated(recursive, semanticModel, cancellationToken).IsEither(Result.Yes, Result.Maybe) && IsInjectedCore(recursive, semanticModel, cancellationToken).IsEither(Result.Yes, Result.Maybe)); } } }
/// <summary> /// Check if any path returns a created IDisposable /// </summary> internal static bool IsPotentiallyCachedOrInjected(InvocationExpressionSyntax disposeCall, SemanticModel semanticModel, CancellationToken cancellationToken) { if (!TryGetDisposedRootMember(disposeCall, semanticModel, cancellationToken, out ExpressionSyntax member)) { return(false); } var symbol = semanticModel.GetSymbolSafe(member, cancellationToken); if (IsInjectedCore(symbol).IsEither(Result.Yes, Result.Maybe)) { return(true); } using (var sources = AssignedValueWalker.Create(symbol, disposeCall, semanticModel, cancellationToken)) { using (var recursive = RecursiveValues.Create(sources.Item, semanticModel, cancellationToken)) { return(IsInjectedCore(recursive, semanticModel, cancellationToken).IsEither(Result.Yes, Result.Maybe)); } } }
private static bool IsNeverNull(ISymbol member, SemanticModel semanticModel, CancellationToken cancellationToken) { if (!(member is IFieldSymbol || member is IPropertySymbol)) { return(false); } using (var sources = AssignedValueWalker.Create(member, semanticModel, cancellationToken)) { foreach (var value in sources.Item) { if (value is ObjectCreationExpressionSyntax) { continue; } return(false); } } return(true); }
private void AddReturnValue(ExpressionSyntax value) { if (this.awaits) { if (AsyncAwait.TryAwaitTaskRun(value, this.semanticModel, this.cancellationToken, out ExpressionSyntax awaited)) { using (var pooled = this.GetRecursive(awaited)) { if (pooled.Item.values.Count == 0) { this.values.Add(awaited); } else { foreach (var returnValue in pooled.Item.values) { this.AddReturnValue(returnValue); } } } return; } if (AsyncAwait.TryAwaitTaskFromResult(value, this.semanticModel, this.cancellationToken, out awaited)) { this.AddReturnValue(awaited); return; } if (this.search == Search.Recursive && value is AwaitExpressionSyntax @await) { value = @await.Expression; } } if (this.search == Search.Recursive) { if (value is InvocationExpressionSyntax invocation) { var method = this.semanticModel.GetSymbolSafe(invocation, this.cancellationToken); if (method == null || method.DeclaringSyntaxReferences.Length == 0) { this.values.Add(value); } else { using (var pooled = this.GetRecursive(value)) { foreach (var returnValue in pooled.Item.values) { this.AddReturnValue(returnValue); } } } } else if (this.recursionLoop.Add(value) && this.semanticModel.IsEither <IParameterSymbol, ILocalSymbol>(value, this.cancellationToken)) { using (var pooled = AssignedValueWalker.Create(value, this.semanticModel, this.cancellationToken)) { if (pooled.Item.Count == 0) { this.values.Add(value); } else { foreach (var assignment in pooled.Item) { this.AddReturnValue(assignment); } } } } else { this.values.Add(value); } } else { this.values.Add(value); } }
/// <summary> /// Check if any path returns a created IDisposable /// </summary> internal static Result IsAssignedWithCreated(ExpressionSyntax disposable, SemanticModel semanticModel, CancellationToken cancellationToken, out ISymbol assignedSymbol) { if (!IsPotentiallyAssignableTo(disposable, semanticModel, cancellationToken)) { assignedSymbol = null; return(Result.No); } if (semanticModel.GetSymbolSafe(disposable, cancellationToken) is IPropertySymbol property && property.TryGetSetter(cancellationToken, out AccessorDeclarationSyntax setter)) { using (var pooledSet = SetPool <ISymbol> .Create()) { using (var pooledAssigned = Assignment.Create(setter, Search.Recursive, semanticModel, cancellationToken)) { foreach (var assigned in pooledAssigned.Item.Assignments) { var symbol = semanticModel.GetSymbolSafe(assigned.Left, cancellationToken); if (IsPotentiallyAssignableTo(assigned.Left, semanticModel, cancellationToken) && (symbol is IFieldSymbol || symbol is IPropertySymbol)) { pooledSet.Item.Add(symbol).IgnoreReturnValue(); } } } assignedSymbol = null; var result = Result.No; foreach (var symbol in pooledSet.Item) { switch (IsAssignedWithCreated(symbol, disposable, semanticModel, cancellationToken)) { case Result.Unknown: if (result == Result.No) { assignedSymbol = symbol; result = Result.Unknown; } break; case Result.Yes: assignedSymbol = symbol; return(Result.Yes); case Result.No: break; case Result.Maybe: assignedSymbol = symbol; result = Result.Maybe; break; default: throw new ArgumentOutOfRangeException(); } } return(result); } } using (var pooled = AssignedValueWalker.Create(disposable, semanticModel, cancellationToken)) { using (var recursive = RecursiveValues.Create(pooled.Item, semanticModel, cancellationToken)) { assignedSymbol = pooled.Item.CurrentSymbol; return(IsAssignedWithCreated(recursive, semanticModel, cancellationToken)); } } }
private bool AddRecursiveValues(ExpressionSyntax assignedValue) { if (assignedValue == null || assignedValue.IsMissing || !this.checkedLocations.Add(assignedValue)) { return(false); } if (assignedValue is LiteralExpressionSyntax || assignedValue is DefaultExpressionSyntax || assignedValue is TypeOfExpressionSyntax || assignedValue is ObjectCreationExpressionSyntax || assignedValue is ArrayCreationExpressionSyntax || assignedValue is ImplicitArrayCreationExpressionSyntax || assignedValue is InitializerExpressionSyntax) { this.values.Add(assignedValue); return(true); } var argument = assignedValue.Parent as ArgumentSyntax; if (argument?.RefOrOutKeyword.IsKind(SyntaxKind.OutKeyword) == true) { var invocation = assignedValue.FirstAncestor <InvocationExpressionSyntax>(); var invokedMethod = this.semanticModel.GetSymbolSafe(invocation, this.cancellationToken); if (invokedMethod == null || invokedMethod.DeclaringSyntaxReferences.Length == 0) { this.values.Add(invocation); return(true); } var before = this.values.Count; foreach (var reference in invokedMethod.DeclaringSyntaxReferences) { var methodDeclaration = reference.GetSyntax(this.cancellationToken) as MethodDeclarationSyntax; if (methodDeclaration.TryGetMatchingParameter(argument, out ParameterSyntax parameter)) { using (var pooled = AssignedValueWalker.Create(this.semanticModel.GetDeclaredSymbolSafe(parameter, this.cancellationToken), this.semanticModel, this.cancellationToken)) { pooled.Item.HandleInvoke(invokedMethod, invocation.ArgumentList); return(this.AddManyRecursively(pooled.Item)); } } } return(before != this.values.Count); } if (assignedValue is BinaryExpressionSyntax binaryExpression) { switch (binaryExpression.Kind()) { case SyntaxKind.CoalesceExpression: var left = this.AddRecursiveValues(binaryExpression.Left); var right = this.AddRecursiveValues(binaryExpression.Right); return(left || right); case SyntaxKind.AsExpression: return(this.AddRecursiveValues(binaryExpression.Left)); default: return(false); } } if (assignedValue is CastExpressionSyntax cast) { return(this.AddRecursiveValues(cast.Expression)); } if (assignedValue is ConditionalExpressionSyntax conditional) { var whenTrue = this.AddRecursiveValues(conditional.WhenTrue); var whenFalse = this.AddRecursiveValues(conditional.WhenFalse); return(whenTrue || whenFalse); } if (assignedValue is AwaitExpressionSyntax @await) { using (var pooled = ReturnValueWalker.Create(@await, Search.Recursive, this.semanticModel, this.cancellationToken)) { return(this.AddManyRecursively(pooled.Item)); } } if (assignedValue is ElementAccessExpressionSyntax) { this.values.Add(assignedValue); return(true); } var symbol = this.semanticModel.GetSymbolSafe(assignedValue, this.cancellationToken); if (symbol == null) { return(false); } if (symbol is IFieldSymbol) { this.values.Add(assignedValue); return(true); } if (symbol is IParameterSymbol) { this.values.Add(assignedValue); using (var pooled = AssignedValueWalker.Create(assignedValue, this.semanticModel, this.cancellationToken)) { return(this.AddManyRecursively(pooled.Item)); } } if (symbol is ILocalSymbol) { using (var pooled = AssignedValueWalker.Create(assignedValue, this.semanticModel, this.cancellationToken)) { return(this.AddManyRecursively(pooled.Item)); } } if (symbol is IPropertySymbol property) { if (property.DeclaringSyntaxReferences.Length == 0) { this.values.Add(assignedValue); return(true); } using (var returnValues = ReturnValueWalker.Create(assignedValue, Search.Recursive, this.semanticModel, this.cancellationToken)) { return(this.AddManyRecursively(returnValues.Item)); } } if (symbol is IMethodSymbol method) { if (method.DeclaringSyntaxReferences.Length == 0) { this.values.Add(assignedValue); return(true); } using (var pooled = ReturnValueWalker.Create(assignedValue, Search.Recursive, this.semanticModel, this.cancellationToken)) { return(this.AddManyRecursively(pooled.Item)); } } return(false); }
private static Result IsInjectedCore(RecursiveValues values, SemanticModel semanticModel, CancellationToken cancellationToken) { if (values.Count == 0) { return(Result.No); } var result = Result.No; values.Reset(); while (values.MoveNext()) { if (values.Current is ElementAccessExpressionSyntax elementAccess) { var symbol = semanticModel.GetSymbolSafe(elementAccess.Expression, cancellationToken); var isInjected = IsInjectedCore(symbol); if (isInjected == Result.Yes) { return(Result.Yes); } if (isInjected == Result.Maybe) { result = Result.Maybe; } using (var sources = AssignedValueWalker.Create(values.Current, semanticModel, cancellationToken)) { using (var recursive = RecursiveValues.Create(sources.Item, semanticModel, cancellationToken)) { isInjected = IsInjectedCore(recursive, semanticModel, cancellationToken); if (isInjected == Result.Yes) { return(Result.Yes); } if (isInjected == Result.Maybe) { result = Result.Maybe; } } } } else { var symbol = semanticModel.GetSymbolSafe(values.Current, cancellationToken); var isInjected = IsInjectedCore(symbol); if (isInjected == Result.Yes) { return(Result.Yes); } if (isInjected == Result.Maybe) { result = Result.Maybe; } } } return(result); }