private static Fix CreateFix(Diagnostic diagnostic, SyntaxNode syntaxRoot, SemanticModel semanticModel, CancellationToken cancellationToken, bool usesUnderscoreNames) { var token = syntaxRoot.FindToken(diagnostic.Location.SourceSpan.Start); if (string.IsNullOrEmpty(token.ValueText) || token.IsMissing) { return(default(Fix)); } var member = (MemberDeclarationSyntax)syntaxRoot.FindNode(diagnostic.Location.SourceSpan); if (member is MethodDeclarationSyntax methodDeclaration) { var method = semanticModel.GetDeclaredSymbolSafe(methodDeclaration, cancellationToken); if (method.Parameters.Length != 1) { return(default(Fix)); } var overridden = method.OverriddenMethod; var baseCall = SyntaxFactory.ParseStatement($"base.{overridden.Name}({method.Parameters[0].Name});") .WithLeadingTrivia(SyntaxFactory.ElasticMarker) .WithTrailingTrivia(SyntaxFactory.ElasticMarker); return(new Fix(baseCall, methodDeclaration)); } if (!TryGetMemberSymbol(member, semanticModel, cancellationToken, out ISymbol memberSymbol)) { return(default(Fix)); } if (Disposable.TryGetDisposeMethod(memberSymbol.ContainingType, Search.TopLevel, out IMethodSymbol disposeMethodSymbol)) { if (disposeMethodSymbol.DeclaredAccessibility == Accessibility.Public && disposeMethodSymbol.Parameters.Length == 0 && disposeMethodSymbol.TryGetSingleDeclaration(cancellationToken, out MethodDeclarationSyntax disposeMethodDeclaration)) { var disposeStatement = CreateDisposeStatement(memberSymbol, semanticModel, cancellationToken, usesUnderscoreNames); return(new Fix(disposeStatement, disposeMethodDeclaration)); } if (disposeMethodSymbol.Parameters.Length == 1 && disposeMethodSymbol.TryGetSingleDeclaration(cancellationToken, out disposeMethodDeclaration)) { var parameterType = semanticModel.GetTypeInfoSafe(disposeMethodDeclaration.ParameterList.Parameters[0]?.Type, cancellationToken).Type; if (parameterType == KnownSymbol.Boolean) { var disposeStatement = CreateDisposeStatement(memberSymbol, semanticModel, cancellationToken, usesUnderscoreNames); return(new Fix(disposeStatement, disposeMethodDeclaration)); } } } return(default(Fix)); }
private static void CheckThatIDisposalbeIsImplemented(SyntaxNodeAnalysisContext context) { var containingType = context.ContainingSymbol.ContainingType; if (!Disposable.IsAssignableTo(containingType) || !Disposable.TryGetDisposeMethod(containingType, Search.TopLevel, out IMethodSymbol _)) { context.ReportDiagnostic(Diagnostic.Create(Descriptor, context.Node.GetLocation())); } }
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); }