private static async Task <Document> UsePatternMatchingAsync( Document document, IfStatementSyntax ifStatement, CancellationToken cancellationToken) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); IsKindExpressionInfo isKindExpression = IsKindExpressionInfo.Create(ifStatement.Condition, semanticModel, cancellationToken: cancellationToken); switch (isKindExpression.Style) { case IsKindExpressionStyle.IsKind: case IsKindExpressionStyle.IsKindConditional: case IsKindExpressionStyle.Kind: case IsKindExpressionStyle.KindConditional: { var block = (BlockSyntax)ifStatement.Statement; IsPatternExpressionSyntax isPatternExpression = CreateIsPatternExpression(block.Statements[0]); BlockSyntax newBlock = block.WithStatements(block.Statements.RemoveAt(0)); IfStatementSyntax newIfStatement = ifStatement.Update( ifStatement.IfKeyword, ifStatement.OpenParenToken, isPatternExpression, ifStatement.CloseParenToken, newBlock, ifStatement.Else); newIfStatement = newIfStatement.WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(ifStatement, newIfStatement, cancellationToken).ConfigureAwait(false)); } case IsKindExpressionStyle.NotIsKind: case IsKindExpressionStyle.NotIsKindConditional: case IsKindExpressionStyle.NotKind: case IsKindExpressionStyle.NotKindConditional: { StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(ifStatement); SyntaxList <StatementSyntax> statements = statementsInfo.Statements; int index = statements.IndexOf(ifStatement); IsPatternExpressionSyntax isPatternExpression = CreateIsPatternExpression(statements[index + 1]); IfStatementSyntax newIfStatement = ifStatement.WithCondition(LogicalNotExpression(isPatternExpression.Parenthesize()).WithTriviaFrom(ifStatement.Condition)); SyntaxList <StatementSyntax> newStatements = statements .ReplaceAt(index, newIfStatement) .RemoveAt(index + 1); return(await document.ReplaceStatementsAsync(statementsInfo, newStatements, cancellationToken).ConfigureAwait(false)); } default: { throw new InvalidOperationException(); } } IsPatternExpressionSyntax CreateIsPatternExpression(StatementSyntax statement) { SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo((LocalDeclarationStatementSyntax)statement); var castExpression = (CastExpressionSyntax)localInfo.Value; return(IsPatternExpression( isKindExpression.Expression, DeclarationPattern(castExpression.Type, SingleVariableDesignation(localInfo.Identifier)))); } }
private static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context) { var ifStatement = (IfStatementSyntax)context.Node; SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; IsKindExpressionInfo isKindExpression = IsKindExpressionInfo.Create(ifStatement.Condition, semanticModel, cancellationToken: cancellationToken); if (!isKindExpression.Success) { return; } Optional <object> optionalConstantValue = semanticModel.GetConstantValue(isKindExpression.KindExpression, cancellationToken); if (!optionalConstantValue.HasValue) { return; } if (!(optionalConstantValue.Value is ushort value)) { return; } if (!_syntaxKindValuesToNames.TryGetValue(value, out string name)) { return; } if (!_syntaxKindNames.Contains(name)) { return; } switch (isKindExpression.Style) { case IsKindExpressionStyle.IsKind: case IsKindExpressionStyle.IsKindConditional: case IsKindExpressionStyle.Kind: case IsKindExpressionStyle.KindConditional: { if (!(ifStatement.Statement is BlockSyntax block)) { return; } Analyze(block.Statements.FirstOrDefault()); break; } case IsKindExpressionStyle.NotIsKind: case IsKindExpressionStyle.NotIsKindConditional: case IsKindExpressionStyle.NotKind: case IsKindExpressionStyle.NotKindConditional: { if (ifStatement.Else != null) { return; } StatementSyntax statement = ifStatement.Statement.SingleNonBlockStatementOrDefault(); if (statement == null) { return; } if (!CSharpFacts.IsJumpStatement(statement.Kind())) { return; } Analyze(ifStatement.NextStatement()); break; } } void Analyze(StatementSyntax statement) { SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(statement); if (!localInfo.Success) { return; } if (!(localInfo.Value is CastExpressionSyntax castExpression)) { return; } if (!IsFixableSyntaxSymbol(castExpression.Type, name, semanticModel, cancellationToken)) { return; } if (!CSharpFactory.AreEquivalent(isKindExpression.Expression, castExpression.Expression)) { return; } context.ReportDiagnostic(DiagnosticDescriptors.UsePatternMatching, ifStatement.IfKeyword); } }