public static Task <Document> RefactorAsync( Document document, IfStatementSyntax ifStatement, CancellationToken cancellationToken) { var statement = (ExpressionStatementSyntax)ifStatement.SingleNonBlockStatementOrDefault(); SimpleMemberInvocationStatementInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationStatementInfo(statement); int insertIndex = invocationInfo.Expression.Span.End - statement.FullSpan.Start; StatementSyntax newStatement = SyntaxFactory.ParseStatement(statement.ToFullString().Insert(insertIndex, "?")); IEnumerable <SyntaxTrivia> leading = ifStatement.DescendantTrivia(TextSpan.FromBounds(ifStatement.SpanStart, statement.SpanStart)); newStatement = (leading.All(f => f.IsWhitespaceOrEndOfLineTrivia())) ? newStatement.WithLeadingTrivia(ifStatement.GetLeadingTrivia()) : newStatement.WithLeadingTrivia(ifStatement.GetLeadingTrivia().Concat(leading)); IEnumerable <SyntaxTrivia> trailing = ifStatement.DescendantTrivia(TextSpan.FromBounds(statement.Span.End, ifStatement.Span.End)); newStatement = (leading.All(f => f.IsWhitespaceOrEndOfLineTrivia())) ? newStatement.WithTrailingTrivia(ifStatement.GetTrailingTrivia()) : newStatement.WithTrailingTrivia(trailing.Concat(ifStatement.GetTrailingTrivia())); return(document.ReplaceNodeAsync(ifStatement, newStatement, cancellationToken)); }
public static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context, INamedTypeSymbol expressionType) { var ifStatement = (IfStatementSyntax)context.Node; if (!ifStatement.IsSimpleIf()) { return; } if (ifStatement.ContainsDiagnostics) { return; } if (ifStatement.SpanContainsDirectives()) { return; } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, allowedStyles: NullCheckStyles.NotEqualsToNull); if (!nullCheck.Success) { return; } SimpleMemberInvocationStatementInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationStatementInfo(ifStatement.SingleNonBlockStatementOrDefault()); if (!invocationInfo.Success) { return; } if (!CSharpFactory.AreEquivalent(nullCheck.Expression, invocationInfo.Expression)) { return; } if (ifStatement.IsInExpressionTree(expressionType, context.SemanticModel, context.CancellationToken)) { return; } context.ReportDiagnostic(DiagnosticDescriptors.UseConditionalAccess, ifStatement); }
public static async Task <Document> RefactorAsync( Document document, IfStatementSyntax ifStatement, CancellationToken cancellationToken) { var statement = (ExpressionStatementSyntax)ifStatement.SingleNonBlockStatementOrDefault(); StatementSyntax newStatement = statement; NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, NullCheckStyles.NotEqualsToNull); SimpleMemberInvocationStatementInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationStatementInfo(statement); ExpressionSyntax expression = invocationInfo.Expression; SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); if (semanticModel.GetTypeSymbol(nullCheck.Expression, cancellationToken).IsNullableType()) { var memberAccess = (MemberAccessExpressionSyntax)invocationInfo.Expression; newStatement = statement.ReplaceNode(memberAccess, memberAccess.Expression.WithTrailingTrivia(memberAccess.GetTrailingTrivia())); expression = memberAccess.Expression; } int insertIndex = expression.Span.End - statement.FullSpan.Start; newStatement = SyntaxFactory.ParseStatement(newStatement.ToFullString().Insert(insertIndex, "?")); IEnumerable <SyntaxTrivia> leading = ifStatement.DescendantTrivia(TextSpan.FromBounds(ifStatement.SpanStart, statement.SpanStart)); newStatement = (leading.All(f => f.IsWhitespaceOrEndOfLineTrivia())) ? newStatement.WithLeadingTrivia(ifStatement.GetLeadingTrivia()) : newStatement.WithLeadingTrivia(ifStatement.GetLeadingTrivia().Concat(leading)); IEnumerable <SyntaxTrivia> trailing = ifStatement.DescendantTrivia(TextSpan.FromBounds(statement.Span.End, ifStatement.Span.End)); newStatement = (leading.All(f => f.IsWhitespaceOrEndOfLineTrivia())) ? newStatement.WithTrailingTrivia(ifStatement.GetTrailingTrivia()) : newStatement.WithTrailingTrivia(trailing.Concat(ifStatement.GetTrailingTrivia())); return(await document.ReplaceNodeAsync(ifStatement, newStatement, cancellationToken).ConfigureAwait(false)); }
public static Task <Document> RefactorAsync( Document document, IfStatementSyntax ifStatement, CancellationToken cancellationToken = default) { StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(ifStatement); SyntaxList <StatementSyntax> statements = statementsInfo.Statements; int index = statements.IndexOf(ifStatement); StatementSyntax expressionStatement = (ExpressionStatementSyntax)statements[index + 1]; SimpleMemberInvocationStatementInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationStatementInfo((ExpressionStatementSyntax)expressionStatement); ExpressionSyntax expression = invocationInfo.Expression; SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo((ExpressionStatementSyntax)ifStatement.SingleNonBlockStatementOrDefault()); BinaryExpressionSyntax coalesceExpression = CSharpFactory.CoalesceExpression(expression.WithoutTrivia(), ParenthesizedExpression(assignmentInfo.AssignmentExpression)); ParenthesizedExpressionSyntax newExpression = ParenthesizedExpression(coalesceExpression) .WithTriviaFrom(expression); StatementSyntax newExpressionStatement = expressionStatement.ReplaceNode(expression, newExpression); IEnumerable <SyntaxTrivia> trivia = statementsInfo.Parent.DescendantTrivia(TextSpan.FromBounds(ifStatement.FullSpan.Start, expressionStatement.FullSpan.Start)); if (trivia.Any(f => !f.IsWhitespaceOrEndOfLineTrivia())) { newExpressionStatement = newExpressionStatement.PrependToLeadingTrivia(trivia); } SyntaxList <StatementSyntax> newStatements = statements .Replace(expressionStatement, newExpressionStatement) .RemoveAt(index); return(document.ReplaceStatementsAsync(statementsInfo, newStatements, cancellationToken)); }
private static void AnalyzeUsingStatement(SyntaxNodeAnalysisContext context) { var usingStatement = (UsingStatementSyntax)context.Node; StatementSyntax statement = usingStatement.Statement; if (statement?.Kind() != SyntaxKind.Block) { return; } var block = (BlockSyntax)statement; StatementSyntax lastStatement = block.Statements.LastOrDefault(); if (lastStatement == null) { return; } if (lastStatement.SpanContainsDirectives()) { return; } SimpleMemberInvocationStatementInfo info = SyntaxInfo.SimpleMemberInvocationStatementInfo(lastStatement); if (!info.Success) { return; } if (info.Arguments.Any()) { return; } string methodName = info.NameText; if (methodName != "Dispose" && methodName != "Close") { return; } ExpressionSyntax usingExpression = usingStatement.Expression; if (usingExpression != null) { if (CSharpFactory.AreEquivalent(info.Expression, usingExpression)) { ReportDiagnostic(context, info.Statement, methodName); } } else { VariableDeclarationSyntax usingDeclaration = usingStatement.Declaration; if (usingDeclaration != null && info.Expression.Kind() == SyntaxKind.IdentifierName) { var identifierName = (IdentifierNameSyntax)info.Expression; VariableDeclaratorSyntax declarator = usingDeclaration.Variables.LastOrDefault(); if (declarator != null && declarator.Identifier.ValueText == identifierName.Identifier.ValueText) { ISymbol symbol = context.SemanticModel.GetDeclaredSymbol(declarator, context.CancellationToken); if (symbol?.Equals(context.SemanticModel.GetSymbol(identifierName, context.CancellationToken)) == true) { ReportDiagnostic(context, info.Statement, methodName); } } } } }
private static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context) { var ifStatement = (IfStatementSyntax)context.Node; if (ifStatement.ContainsDiagnostics) { return; } if (ifStatement.SpanContainsDirectives()) { return; } if (!ifStatement.IsSimpleIf()) { return; } SyntaxList <StatementSyntax> statements = SyntaxInfo.StatementListInfo(ifStatement).Statements; if (!statements.Any()) { return; } if (IsPartOfLazyInitialization()) { return; } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo( ifStatement.Condition, semanticModel: context.SemanticModel, allowedStyles: NullCheckStyles.CheckingNull, cancellationToken: context.CancellationToken); if (!nullCheck.Success) { return; } SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(ifStatement.SingleNonBlockStatementOrDefault()); if (!assignmentInfo.Success) { return; } if (!CSharpFactory.AreEquivalent(assignmentInfo.Left, nullCheck.Expression)) { return; } if (!assignmentInfo.Right.IsSingleLine()) { return; } int index = statements.IndexOf(ifStatement); if (index > 0 && !context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseCoalesceExpression)) { StatementSyntax previousStatement = statements[index - 1]; if (!previousStatement.ContainsDiagnostics && !previousStatement.GetTrailingTrivia().Any(f => f.IsDirective) && !ifStatement.GetLeadingTrivia().Any(f => f.IsDirective) && CanUseCoalesceExpression(previousStatement, nullCheck.Expression)) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseCoalesceExpression, previousStatement); } } if (context.IsAnalyzerSuppressed(DiagnosticDescriptors.InlineLazyInitialization)) { return; } if (index == statements.Count - 1) { return; } StatementSyntax nextStatement = statements[index + 1]; if (nextStatement.ContainsDiagnostics) { return; } SimpleMemberInvocationStatementInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationStatementInfo(nextStatement); if (!invocationInfo.Success) { return; } if (!CSharpFactory.AreEquivalent(nullCheck.Expression, invocationInfo.Expression)) { return; } if (ifStatement.GetTrailingTrivia().Any(f => f.IsDirective)) { return; } if (nextStatement.SpanOrLeadingTriviaContainsDirectives()) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.InlineLazyInitialization, ifStatement); bool IsPartOfLazyInitialization() { return(statements.Count == 2 && statements.IndexOf(ifStatement) == 0 && statements[1].IsKind(SyntaxKind.ReturnStatement)); } }
public static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context, INamedTypeSymbol expressionOfTSymbol) { var ifStatement = (IfStatementSyntax)context.Node; if (!ifStatement.IsSimpleIf()) { return; } if (ifStatement.ContainsDiagnostics) { return; } if (ifStatement.SpanContainsDirectives()) { return; } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, allowedStyles: NullCheckStyles.NotEqualsToNull); ExpressionSyntax expression = nullCheck.Expression; if (expression == null) { return; } SimpleMemberInvocationStatementInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationStatementInfo(ifStatement.SingleNonBlockStatementOrDefault()); ExpressionSyntax expression2 = invocationInfo.Expression; if (expression2 == null) { return; } ITypeSymbol typeSymbol = context.SemanticModel.GetTypeSymbol(expression); if (typeSymbol == null) { return; } if (typeSymbol.IsNullableType()) { if (!expression2.IsKind(SyntaxKind.SimpleMemberAccessExpression)) { return; } var memberAccess = (MemberAccessExpressionSyntax)expression2; if (!(memberAccess.Name is IdentifierNameSyntax identifierName)) { return; } if (!string.Equals(identifierName.Identifier.ValueText, "Value", StringComparison.Ordinal)) { return; } expression2 = memberAccess.Expression; } if (!CSharpFactory.AreEquivalent(expression, expression2)) { return; } if (ifStatement.IsInExpressionTree(expressionOfTSymbol, context.SemanticModel, context.CancellationToken)) { return; } context.ReportDiagnostic(DiagnosticDescriptors.UseConditionalAccess, ifStatement); }
public static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context) { var ifStatement = (IfStatementSyntax)context.Node; if (!ifStatement.IsSimpleIf()) { return; } if (ifStatement.ContainsDiagnostics) { return; } if (ifStatement.SpanContainsDirectives()) { return; } SyntaxList <StatementSyntax> statements = SyntaxInfo.StatementListInfo(ifStatement).Statements; if (!statements.Any()) { return; } if (IsPartOfLazyInitialization(ifStatement, statements)) { return; } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, semanticModel: context.SemanticModel, cancellationToken: context.CancellationToken); if (!nullCheck.Success) { return; } SimpleAssignmentStatementInfo simpleAssignment = SyntaxInfo.SimpleAssignmentStatementInfo(ifStatement.SingleNonBlockStatementOrDefault()); if (!simpleAssignment.Success) { return; } if (!CSharpFactory.AreEquivalent(simpleAssignment.Left, nullCheck.Expression)) { return; } if (!simpleAssignment.Right.IsSingleLine()) { return; } int index = statements.IndexOf(ifStatement); if (index > 0) { StatementSyntax previousStatement = statements[index - 1]; if (!previousStatement.ContainsDiagnostics && IsFixable(previousStatement, ifStatement, nullCheck.Expression, ifStatement.Parent)) { context.ReportDiagnostic(DiagnosticDescriptors.UseCoalesceExpression, previousStatement); } } if (index == statements.Count - 1) { return; } StatementSyntax nextStatement = statements[index + 1]; if (nextStatement.ContainsDiagnostics) { return; } SimpleMemberInvocationStatementInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationStatementInfo(nextStatement); if (!invocationInfo.Success) { return; } if (!CSharpFactory.AreEquivalent(nullCheck.Expression, invocationInfo.Expression)) { return; } if (ifStatement.Parent.ContainsDirectives(TextSpan.FromBounds(ifStatement.SpanStart, nextStatement.Span.End))) { return; } context.ReportDiagnostic(DiagnosticDescriptors.InlineLazyInitialization, ifStatement); }
public static Task <Document> InlineLazyInitializationAsync( Document document, IfStatementSyntax ifStatement, CancellationToken cancellationToken = default) { StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(ifStatement); var assignmentStatement = (ExpressionStatementSyntax)ifStatement.SingleNonBlockStatementOrDefault(); SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(assignmentStatement, walkDownParentheses: false); ExpressionSyntax right = assignmentInfo.Right; int index = statementsInfo.IndexOf(ifStatement); var expressionStatement2 = (ExpressionStatementSyntax)statementsInfo[index + 1]; SimpleMemberInvocationStatementInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationStatementInfo(expressionStatement2); ExpressionSyntax expression = invocationInfo.Expression; var newLeading = new List <SyntaxTrivia>(ifStatement.GetLeadingTrivia()); ExpressionSyntax coalesceExpression; if (document.SupportsLanguageFeature(CSharpLanguageFeature.NullCoalescingAssignmentOperator)) { AddTrivia(ifStatement.DescendantTrivia(TextSpan.FromBounds(ifStatement.SpanStart, right.SpanStart)).ToSyntaxTriviaList()); coalesceExpression = CoalesceAssignmentExpression(expression.WithoutTrivia(), right.WithoutTrivia()); } else { AddTrivia(ifStatement.DescendantTrivia(TextSpan.FromBounds(ifStatement.SpanStart, assignmentInfo.AssignmentExpression.SpanStart)).ToSyntaxTriviaList()); coalesceExpression = CoalesceExpression(expression.WithoutTrivia(), ParenthesizedExpression(assignmentInfo.AssignmentExpression.WithoutTrivia())); } AddTrivia(ifStatement.DescendantTrivia(TextSpan.FromBounds(right.Span.End, ifStatement.Span.End)).ToSyntaxTriviaList()); AddTrivia(ifStatement.GetTrailingTrivia()); AddTrivia(expressionStatement2.GetLeadingTrivia()); ParenthesizedExpressionSyntax newExpression = ParenthesizedExpression(coalesceExpression) .WithLeadingTrivia(newLeading) .WithTrailingTrivia(expression.GetTrailingTrivia()); StatementSyntax newExpressionStatement = expressionStatement2.ReplaceNode(expression, newExpression); StatementListInfo newStatements = statementsInfo .Replace(expressionStatement2, newExpressionStatement) .RemoveAt(index); return(document.ReplaceStatementsAsync(statementsInfo, newStatements, cancellationToken)); void AddTrivia(SyntaxTriviaList trivia) { if (!trivia.IsEmptyOrWhitespace()) { newLeading.AddRange(trivia); } } }