public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); IfStatementSyntax ifStatement = root .FindNode(context.Span, getInnermostNodeForTie: true)? .FirstAncestorOrSelf <IfStatementSyntax>(); if (ifStatement == null) { return; } ifStatement = ifStatement.GetTopmostIf(); CodeAction codeAction = CodeAction.Create( "Add braces to if-else", cancellationToken => AddBracesToIfElseRefactoring.RefactorAsync(context.Document, ifStatement, cancellationToken), DiagnosticIdentifiers.AddBracesToIfElse + EquivalenceKeySuffix); context.RegisterCodeFix(codeAction, context.Diagnostics); }
private static ReduceIfNestingAnalysisResult AnalyzeCore( IfStatementSyntax ifStatement, SemanticModel semanticModel, SyntaxKind jumpKind, ReduceIfNestingOptions options, CancellationToken cancellationToken = default(CancellationToken)) { StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(ifStatement); if (!statementsInfo.Success) { return(Fail(ifStatement)); } SyntaxNode node = statementsInfo.Parent; SyntaxNode parent = node.Parent; SyntaxKind parentKind = parent.Kind(); SyntaxList <StatementSyntax> statements = statementsInfo.Statements; if (statementsInfo.IsParentSwitchSection || parentKind == SyntaxKind.SwitchSection) { SyntaxNode switchSection = (statementsInfo.IsParentSwitchSection) ? node : parent; if (!options.AllowSwitchSection()) { return(Fail(switchSection)); } if (ifStatement != statements.LastButOneOrDefault()) { return(Fail(switchSection)); } if (!IsFixableJumpStatement(statements.Last(), ref jumpKind)) { return(Fail(switchSection)); } if (!options.AllowNestedFix() && IsNestedFix(switchSection.Parent, semanticModel, options, cancellationToken)) { return(Fail(switchSection)); } return(Success(jumpKind, switchSection)); } if (parentKind.Is( SyntaxKind.ForStatement, SyntaxKind.ForEachStatement, SyntaxKind.DoStatement, SyntaxKind.WhileStatement)) { if (!options.AllowLoop()) { return(Fail(parent)); } StatementSyntax lastStatement = statements.Last(); if (ifStatement == lastStatement) { jumpKind = SyntaxKind.ContinueStatement; } else { if (ifStatement != statements.LastButOneOrDefault()) { return(Fail(parent)); } if (!IsFixableJumpStatement(lastStatement, ref jumpKind)) { return(Fail(parent)); } } if (!options.AllowNestedFix() && IsNestedFix(parent.Parent, semanticModel, options, cancellationToken)) { return(Fail(parent)); } return(Success(jumpKind, parent)); } if (!IsFixable(ifStatement, statements, ref jumpKind)) { return(Fail(node)); } switch (parentKind) { case SyntaxKind.ConstructorDeclaration: case SyntaxKind.DestructorDeclaration: case SyntaxKind.SetAccessorDeclaration: case SyntaxKind.AddAccessorDeclaration: case SyntaxKind.RemoveAccessorDeclaration: { if (jumpKind == SyntaxKind.None) { jumpKind = SyntaxKind.ReturnStatement; } else if (jumpKind != SyntaxKind.ReturnStatement) { return(Fail(parent)); } return(Success(jumpKind, parent)); } case SyntaxKind.OperatorDeclaration: case SyntaxKind.ConversionOperatorDeclaration: case SyntaxKind.GetAccessorDeclaration: { if (jumpKind == SyntaxKind.None) { return(Fail(parent)); } return(Success(jumpKind, parent)); } case SyntaxKind.MethodDeclaration: { var methodDeclaration = (MethodDeclarationSyntax)parent; if (jumpKind != SyntaxKind.None) { return(Success(jumpKind, parent)); } if (methodDeclaration.ReturnsVoid()) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (methodDeclaration.Modifiers.Contains(SyntaxKind.AsyncKeyword) && semanticModel .GetDeclaredSymbol(methodDeclaration, cancellationToken)? .ReturnType .HasMetadataName(MetadataNames.System_Threading_Tasks_Task) == true) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (semanticModel .GetDeclaredSymbol(methodDeclaration, cancellationToken)? .ReturnType .OriginalDefinition .IsIEnumerableOrIEnumerableOfT() == true && methodDeclaration.ContainsYield()) { return(Success(SyntaxKind.YieldBreakStatement, parent)); } break; } case SyntaxKind.LocalFunctionStatement: { var localFunction = (LocalFunctionStatementSyntax)parent; if (jumpKind != SyntaxKind.None) { return(Success(jumpKind, parent)); } if (localFunction.ReturnsVoid()) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (localFunction.Modifiers.Contains(SyntaxKind.AsyncKeyword) && semanticModel.GetDeclaredSymbol(localFunction, cancellationToken)? .ReturnType .HasMetadataName(MetadataNames.System_Threading_Tasks_Task) == true) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (semanticModel.GetDeclaredSymbol(localFunction, cancellationToken)? .ReturnType .OriginalDefinition .IsIEnumerableOrIEnumerableOfT() == true && localFunction.ContainsYield()) { return(Success(SyntaxKind.YieldBreakStatement, parent)); } break; } case SyntaxKind.AnonymousMethodExpression: case SyntaxKind.SimpleLambdaExpression: case SyntaxKind.ParenthesizedLambdaExpression: { var anonymousFunction = (AnonymousFunctionExpressionSyntax)parent; if (jumpKind != SyntaxKind.None) { return(Success(jumpKind, parent)); } if (!(semanticModel.GetSymbol(anonymousFunction, cancellationToken) is IMethodSymbol methodSymbol)) { return(Fail(parent)); } if (methodSymbol.ReturnsVoid) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (anonymousFunction.AsyncKeyword.Kind() == SyntaxKind.AsyncKeyword && methodSymbol.ReturnType.HasMetadataName(MetadataNames.System_Threading_Tasks_Task)) { return(Success(SyntaxKind.ReturnStatement, parent)); } break; } case SyntaxKind.IfStatement: { ifStatement = (IfStatementSyntax)parent; if (ifStatement.Parent is ElseClauseSyntax elseClause) { if (ifStatement.Else != null) { return(Fail(parent)); } if (!options.AllowIfInsideIfElse()) { return(Fail(parent)); } return(AnalyzeCore(ifStatement.GetTopmostIf(), semanticModel, jumpKind, options, cancellationToken)); } else { if (!IsFixable(ifStatement)) { return(Fail(parent)); } if (!options.AllowNestedFix()) { return(Fail(parent)); } return(AnalyzeCore(ifStatement, semanticModel, jumpKind, options, cancellationToken)); } } case SyntaxKind.ElseClause: { if (!options.AllowIfInsideIfElse()) { return(Fail(parent)); } var elseClause = (ElseClauseSyntax)parent; return(AnalyzeCore(elseClause.GetTopmostIf(), semanticModel, jumpKind, options, cancellationToken)); } } return(Fail(parent)); }
private static ReduceIfNestingAnalysis AnalyzeCore( IfStatementSyntax ifStatement, SemanticModel semanticModel, SyntaxKind jumpKind, ReduceIfNestingOptions options, INamedTypeSymbol taskSymbol = null, CancellationToken cancellationToken = default(CancellationToken)) { if (!StatementContainer.TryCreate(ifStatement, out StatementContainer container)) { return(Fail(ifStatement)); } CSharpSyntaxNode node = container.Node; SyntaxNode parent = node.Parent; SyntaxKind parentKind = parent.Kind(); SyntaxList <StatementSyntax> statements = container.Statements; if (container.IsSwitchSection || parentKind == SyntaxKind.SwitchSection) { SyntaxNode switchSection = (container.IsSwitchSection) ? node : parent; if (!options.AllowSwitchSection()) { return(Fail(switchSection)); } if (ifStatement != statements.LastButOneOrDefault()) { return(Fail(switchSection)); } if (!IsFixableJumpStatement(statements.Last(), ref jumpKind)) { return(Fail(switchSection)); } if (!options.AllowNestedFix() && IsNestedFix(switchSection.Parent, semanticModel, options, taskSymbol, cancellationToken)) { return(Fail(switchSection)); } return(Success(jumpKind, switchSection)); } if (parentKind.Is( SyntaxKind.ForStatement, SyntaxKind.ForEachStatement, SyntaxKind.DoStatement, SyntaxKind.WhileStatement)) { if (!options.AllowLoop()) { return(Fail(parent)); } StatementSyntax lastStatement = statements.Last(); if (ifStatement == lastStatement) { jumpKind = SyntaxKind.ContinueStatement; } else { if (ifStatement != statements.LastButOneOrDefault()) { return(Fail(parent)); } if (!IsFixableJumpStatement(lastStatement, ref jumpKind)) { return(Fail(parent)); } } if (!options.AllowNestedFix() && IsNestedFix(parent.Parent, semanticModel, options, taskSymbol, cancellationToken)) { return(Fail(parent)); } return(Success(jumpKind, parent)); } if (!IsFixable(ifStatement, statements, ref jumpKind)) { return(Fail(node)); } switch (parentKind) { case SyntaxKind.ConstructorDeclaration: case SyntaxKind.DestructorDeclaration: case SyntaxKind.SetAccessorDeclaration: case SyntaxKind.AddAccessorDeclaration: case SyntaxKind.RemoveAccessorDeclaration: { if (jumpKind == SyntaxKind.None) { jumpKind = SyntaxKind.ReturnStatement; } else if (jumpKind != SyntaxKind.ReturnStatement) { return(Fail(parent)); } return(Success(jumpKind, parent)); } case SyntaxKind.OperatorDeclaration: case SyntaxKind.ConversionOperatorDeclaration: case SyntaxKind.GetAccessorDeclaration: { if (jumpKind == SyntaxKind.None) { return(Fail(parent)); } return(Success(jumpKind, parent)); } case SyntaxKind.MethodDeclaration: { var methodDeclaration = (MethodDeclarationSyntax)parent; if (jumpKind != SyntaxKind.None) { return(Success(jumpKind, parent)); } if (methodDeclaration.ReturnsVoid()) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (methodDeclaration.Modifiers.Contains(SyntaxKind.AsyncKeyword) && taskSymbol != null && semanticModel .GetDeclaredSymbol(methodDeclaration, cancellationToken)? .ReturnType .Equals(taskSymbol) == true) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (semanticModel .GetDeclaredSymbol(methodDeclaration, cancellationToken)? .ReturnType .IsIEnumerableOrConstructedFromIEnumerableOfT() == true && methodDeclaration.ContainsYield()) { return(Success(SyntaxKind.YieldBreakStatement, parent)); } break; } case SyntaxKind.LocalFunctionStatement: { var localFunction = (LocalFunctionStatementSyntax)parent; if (jumpKind != SyntaxKind.None) { return(Success(jumpKind, parent)); } if (localFunction.ReturnsVoid()) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (localFunction.Modifiers.Contains(SyntaxKind.AsyncKeyword) && taskSymbol != null && ((IMethodSymbol)semanticModel.GetDeclaredSymbol(localFunction, cancellationToken))? .ReturnType .Equals(taskSymbol) == true) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (((IMethodSymbol)semanticModel.GetDeclaredSymbol(localFunction, cancellationToken))? .ReturnType .IsIEnumerableOrConstructedFromIEnumerableOfT() == true && localFunction.ContainsYield()) { return(Success(SyntaxKind.YieldBreakStatement, parent)); } break; } case SyntaxKind.AnonymousMethodExpression: case SyntaxKind.SimpleLambdaExpression: case SyntaxKind.ParenthesizedLambdaExpression: { var anonymousFunction = (AnonymousFunctionExpressionSyntax)parent; if (jumpKind != SyntaxKind.None) { return(Success(jumpKind, parent)); } var methodSymbol = semanticModel.GetSymbol(anonymousFunction, cancellationToken) as IMethodSymbol; if (methodSymbol == null) { return(Fail(parent)); } if (methodSymbol.ReturnsVoid) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (anonymousFunction.AsyncKeyword.IsKind(SyntaxKind.AsyncKeyword) && methodSymbol.ReturnType.Equals(taskSymbol)) { return(Success(SyntaxKind.ReturnStatement, parent)); } break; } case SyntaxKind.IfStatement: { ifStatement = (IfStatementSyntax)parent; if (ifStatement.Parent is ElseClauseSyntax elseClause) { if (ifStatement.Else != null) { return(Fail(parent)); } if (!options.AllowIfInsideIfElse()) { return(Fail(parent)); } return(AnalyzeCore(ifStatement.GetTopmostIf(), semanticModel, jumpKind, options, taskSymbol, cancellationToken)); } else { if (!IsFixable(ifStatement)) { return(Fail(parent)); } if (!options.AllowNestedFix()) { return(Fail(parent)); } return(AnalyzeCore(ifStatement, semanticModel, jumpKind, options, taskSymbol, cancellationToken)); } } case SyntaxKind.ElseClause: { if (!options.AllowIfInsideIfElse()) { return(Fail(parent)); } var elseClause = (ElseClauseSyntax)parent; return(AnalyzeCore(elseClause.GetTopmostIf(), semanticModel, jumpKind, options, taskSymbol, cancellationToken)); } } return(Fail(parent)); }
private static bool IsFixableIfElseWithReturnOrContinueInsideIf(IfStatementSyntax ifStatement, ElseClauseSyntax elseClause) { if (elseClause.Statement?.IsKind(SyntaxKind.IfStatement) != false) { return(false); } IfStatementSyntax topmostIf = ifStatement.GetTopmostIf(); if (!(topmostIf.Parent is BlockSyntax block)) { return(false); } if (!block.Statements.IsLast(topmostIf, ignoreLocalFunctions: true)) { return(false); } switch (block.Parent.Kind()) { case SyntaxKind.MethodDeclaration: case SyntaxKind.LocalFunctionStatement: case SyntaxKind.ConstructorDeclaration: case SyntaxKind.DestructorDeclaration: case SyntaxKind.AddAccessorDeclaration: case SyntaxKind.RemoveAccessorDeclaration: case SyntaxKind.SetAccessorDeclaration: { //void M() //{ // if (x) // { // return; // } // else // { // M(); // } return(ifStatement.SingleNonBlockStatementOrDefault() is ReturnStatementSyntax returnStatement && returnStatement.Expression == null); } case SyntaxKind.ForEachStatement: case SyntaxKind.ForEachVariableStatement: case SyntaxKind.ForStatement: case SyntaxKind.WhileStatement: { //while (x) //{ // if (y) // { // continue; // } // else // { // M(); // } //} return(ifStatement.SingleNonBlockStatementOrDefault().IsKind(SyntaxKind.ContinueStatement)); } } return(false); }