internal static bool TryGetDisposedRootMember(InvocationExpressionSyntax disposeCall, SemanticModel semanticModel, CancellationToken cancellationToken, out ExpressionSyntax disposedMember) { if (MemberPath.TryFindRootMember(disposeCall, out disposedMember)) { var property = semanticModel.GetSymbolSafe(disposedMember, cancellationToken) as IPropertySymbol; if (property == null || property.IsAutoProperty(cancellationToken)) { return(true); } if (property.GetMethod == null) { return(false); } foreach (var reference in property.GetMethod.DeclaringSyntaxReferences) { var node = reference.GetSyntax(cancellationToken); using (var pooled = ReturnValueWalker.Create(node, Search.TopLevel, semanticModel, cancellationToken)) { if (pooled.Item.Count == 0) { return(false); } return(MemberPath.TryFindRootMember(pooled.Item[0], out disposedMember)); } } } return(false); }
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)); } } }
/// <summary> /// Check if any path returns a created IDisposable /// </summary> internal static Result IsCreation(ExpressionSyntax candidate, SemanticModel semanticModel, CancellationToken cancellationToken) { if (!IsPotentiallyAssignableTo(candidate, semanticModel, cancellationToken) || candidate is ThisExpressionSyntax || candidate is BaseExpressionSyntax) { return(Result.No); } if (candidate is ObjectCreationExpressionSyntax) { return(Result.Yes); } using (var pooled = ReturnValueWalker.Create(candidate, Search.Recursive, semanticModel, cancellationToken)) { if (pooled.Item.Count == 0) { var symbol = semanticModel.GetSymbolSafe(candidate, cancellationToken); if (symbol != null && symbol.DeclaringSyntaxReferences.Length == 0) { return(IsCreationCore(candidate, semanticModel, cancellationToken)); } using (var recursive = RecursiveValues.Create(new[] { candidate }, semanticModel, cancellationToken)) { return(IsCreationCore(recursive, semanticModel, cancellationToken)); } } using (var recursive = RecursiveValues.Create(pooled.Item, semanticModel, cancellationToken)) { return(IsCreationCore(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 bool MustBeHandled( ExpressionSyntax node, SemanticModel semanticModel, CancellationToken cancellationToken) { if (node.Parent is AnonymousFunctionExpressionSyntax || node.Parent is UsingStatementSyntax || node.Parent is EqualsValueClauseSyntax || node.Parent is ReturnStatementSyntax || node.Parent is ArrowExpressionClauseSyntax) { return(false); } if (Disposable.IsCreation(node, semanticModel, cancellationToken) .IsEither(Result.No, Result.Unknown)) { return(false); } if (node.Parent is StatementSyntax) { return(true); } if (node.Parent is ArgumentSyntax argument) { if (argument.Parent.Parent is InvocationExpressionSyntax invocation) { using (var returnWalker = ReturnValueWalker.Create(invocation, Search.Recursive, semanticModel, cancellationToken)) { foreach (var returnValue in returnWalker.Item) { if (MustBeHandled(returnValue, semanticModel, cancellationToken)) { return(true); } } } return(false); } if (argument.Parent.Parent is ObjectCreationExpressionSyntax) { if (TryGetAssignedFieldOrProperty(argument, semanticModel, cancellationToken, out ISymbol member, out IMethodSymbol ctor) && member != null) { var initializer = argument.FirstAncestorOrSelf <ConstructorInitializerSyntax>(); if (initializer != null) { if (semanticModel.GetDeclaredSymbolSafe(initializer.Parent, cancellationToken) is IMethodSymbol chainedCtor && chainedCtor.ContainingType != member.ContainingType) { if (Disposable.TryGetDisposeMethod(chainedCtor.ContainingType, Search.TopLevel, out IMethodSymbol disposeMethod)) { return(!Disposable.IsMemberDisposed(member, disposeMethod, semanticModel, cancellationToken)); } } } if (Disposable.IsMemberDisposed(member, ctor.ContainingType, semanticModel, cancellationToken) .IsEither(Result.Yes, Result.Maybe)) { return(false); } return(true); } return(ctor?.ContainingType != KnownSymbol.StreamReader && ctor?.ContainingType != KnownSymbol.CompositeDisposable); } } return(false); }
private static bool IsReturned(ILocalSymbol symbol, BlockSyntax block, SemanticModel semanticModel, CancellationToken cancellationToken) { using (var pooled = ReturnValueWalker.Create(block, Search.TopLevel, semanticModel, cancellationToken)) { foreach (var value in pooled.Item) { var returnedSymbol = semanticModel.GetSymbolSafe(value, cancellationToken); if (SymbolComparer.Equals(symbol, returnedSymbol)) { return(true); } if (value is ObjectCreationExpressionSyntax objectCreation) { if (objectCreation.ArgumentList != null) { foreach (var argument in objectCreation.ArgumentList.Arguments) { var arg = semanticModel.GetSymbolSafe(argument.Expression, cancellationToken); if (SymbolComparer.Equals(symbol, arg)) { return(true); } } } if (objectCreation.Initializer != null) { foreach (var argument in objectCreation.Initializer.Expressions) { var arg = semanticModel.GetSymbolSafe(argument, cancellationToken); if (SymbolComparer.Equals(symbol, arg)) { return(true); } } } } if (value is InvocationExpressionSyntax invocation) { if (returnedSymbol == KnownSymbol.RxDisposable.Create && invocation.ArgumentList != null && invocation.ArgumentList.Arguments.TryGetSingle(out ArgumentSyntax argument)) { var body = (argument.Expression as ParenthesizedLambdaExpressionSyntax)?.Body; using (var pooledInvocations = InvocationWalker.Create(body)) { foreach (var candidate in pooledInvocations.Item.Invocations) { if (Disposable.IsDisposing(candidate, symbol, semanticModel, cancellationToken)) { return(true); } } } } } } } return(false); }