internal static bool IsFixableRecursively(IfStatementSyntax ifStatement, SyntaxKind jumpKind) { if (!(ifStatement.Statement is BlockSyntax block)) { return(false); } SyntaxList <StatementSyntax> statements = block.Statements; if (!statements.Any()) { return(false); } StatementSyntax statement = statements.Last(); if (statement is IfStatementSyntax ifStatement2) { return(IsFixable(ifStatement2)); } return(jumpKind == GetJumpKind(statement) && (statements.LastButOneOrDefault() is IfStatementSyntax ifStatement3) && IsFixable(ifStatement3)); }
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)); }