public static async Task ComputeRefactoringAsync( RefactoringContext context, LocalDeclarationStatementSyntax localDeclaration) { StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(localDeclaration); if (!statementsInfo.Success) { return; } SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(localDeclaration); if (!localInfo.Success) { return; } if (!context.Span.IsEmptyAndContainedInSpan(localInfo.EqualsToken)) { return; } ExpressionSyntax value = localInfo.Value; if (value == null) { return; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); TypeSyntax type = localInfo.Type; if (type.IsVar) { ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(value, context.CancellationToken); if (typeSymbol?.SupportsExplicitDeclaration() != true) { return; } type = typeSymbol.ToMinimalTypeSyntax(semanticModel, type.SpanStart); } else { ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(type, context.CancellationToken); if (typeSymbol?.IsErrorType() != false) { return; } } context.RegisterRefactoring( "Split declaration and initialization", ct => RefactorAsync(context.Document, localInfo, type, statementsInfo, ct), RefactoringIdentifiers.SplitDeclarationAndInitialization); }
private static bool CanUseCoalesceExpression(StatementSyntax statement, ExpressionSyntax expression) { SyntaxKind kind = statement.Kind(); if (kind == SyntaxKind.LocalDeclarationStatement) { SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo((LocalDeclarationStatementSyntax)statement); return(localInfo.Success && !localInfo.Type.IsKind(SyntaxKind.RefType) && expression.IsKind(SyntaxKind.IdentifierName) && string.Equals(localInfo.IdentifierText, ((IdentifierNameSyntax)expression).Identifier.ValueText, StringComparison.Ordinal) && !localInfo.Value.GetTrailingTrivia().Any(f => f.IsDirective) && !localInfo.SemicolonToken.ContainsDirectives); } else if (kind == SyntaxKind.ExpressionStatement) { var expressionStatement = (ExpressionStatementSyntax)statement; SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(expressionStatement); return(assignmentInfo.Success && CSharpFactory.AreEquivalent(expression, assignmentInfo.Left) && !assignmentInfo.Right.GetTrailingTrivia().Any(f => f.IsDirective) && !expressionStatement.SemicolonToken.ContainsDirectives); } return(false); }
private static Task <Document> ConvertWhileStatementToForStatementAsync( Document document, WhileStatementSyntax whileStatement, CancellationToken cancellationToken) { StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(whileStatement); SyntaxList <StatementSyntax> statements = statementsInfo.Statements; int index = statements.IndexOf(whileStatement); SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo((LocalDeclarationStatementSyntax)statements[index - 1]); var block = (BlockSyntax)whileStatement.Statement; var expressionStatement = (ExpressionStatementSyntax)block.Statements.Last(); var postIncrementExpression = (PostfixUnaryExpressionSyntax)expressionStatement.Expression; BlockSyntax newBlock = block.WithStatements(block.Statements.Remove(expressionStatement)); ForStatementSyntax forStatement = CSharpFactory.ForStatement( declaration: localInfo.Declaration.TrimTrivia(), condition: whileStatement.Condition, incrementor: postIncrementExpression.TrimTrivia(), statement: newBlock); forStatement = forStatement .WithLeadingTrivia(localInfo.Statement.GetLeadingTrivia().AddRange(whileStatement.GetLeadingTrivia().EmptyIfWhitespace())) .WithFormatterAnnotation(); SyntaxList <StatementSyntax> newStatements = statements.ReplaceRange(index - 1, 2, new StatementSyntax[] { forStatement }); return(document.ReplaceStatementsAsync(statementsInfo, newStatements, cancellationToken)); }
public static async Task ComputeRefactoringAsync(RefactoringContext context, VariableDeclarationSyntax variableDeclaration) { if (!(variableDeclaration.Parent is LocalDeclarationStatementSyntax localDeclaration)) { return; } if (!CSharpFacts.CanHaveStatements(localDeclaration.Parent.Kind())) { return; } SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(localDeclaration); if (!localInfo.Success) { return; } if (!context.Span.IsEmptyAndContainedInSpan(localInfo.Identifier)) { return; } ExpressionSyntax value = localInfo.Value; if (value == null) { return; } if (value.Kind() == SyntaxKind.DefaultExpression) { return; } if (value is LiteralExpressionSyntax) { return; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); var typeSymbol = semanticModel.GetTypeSymbol(localInfo.Type, context.CancellationToken) as INamedTypeSymbol; if (typeSymbol?.Implements(SpecialType.System_IDisposable, allInterfaces: true) != true) { return; } context.RegisterRefactoring( $"Using '{localInfo.IdentifierText}'", cancellationToken => RefactorAsync(context.Document, localInfo, semanticModel, cancellationToken), RefactoringIdentifiers.WrapInUsingStatement); }
internal static async Task ComputeRefactoringAsync(RefactoringContext context, VariableDeclarationSyntax variableDeclaration) { SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(variableDeclaration); if (!context.Span.IsContainedInSpanOrBetweenSpans(localInfo.Identifier)) { return; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (!CanRefactor(localInfo, semanticModel, context.CancellationToken)) { return; } RegisterRefactoring(context, IdentifierName(localInfo.Identifier), localInfo.Statement); }
public static async Task ComputeRefactoringAsync(RefactoringContext context, ConditionalExpressionSyntax conditionalExpression) { ExpressionSyntax expression = conditionalExpression.WalkUpParentheses(); SyntaxNode parent = expression.Parent; if (parent.IsKind(SyntaxKind.ReturnStatement, SyntaxKind.YieldReturnStatement)) { context.RegisterRefactoring( Title, cancellationToken => RefactorAsync(context.Document, (StatementSyntax)parent, conditionalExpression, cancellationToken)); } else if (parent is AssignmentExpressionSyntax assignment) { if (assignment.Parent is ExpressionStatementSyntax expressionStatement) { context.RegisterRefactoring( Title, cancellationToken => RefactorAsync(context.Document, expressionStatement, conditionalExpression, cancellationToken)); } } else { SingleLocalDeclarationStatementInfo localDeclarationInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(expression); if (localDeclarationInfo.Success) { TypeSyntax type = localDeclarationInfo.Type; if (type != null) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (!type.IsVar || semanticModel.GetTypeSymbol(type, context.CancellationToken)?.SupportsExplicitDeclaration() == true) { context.RegisterRefactoring( Title, cancellationToken => RefactorAsync(context.Document, localDeclarationInfo.Statement, conditionalExpression, semanticModel, cancellationToken)); } } } } }
internal static async Task ComputeRefactoringAsync(RefactoringContext context, StatementListSelection selectedStatements) { if (selectedStatements.Count <= 1) { return; } StatementSyntax statement = selectedStatements.First(); SyntaxKind kind = statement.Kind(); if (kind == SyntaxKind.LocalDeclarationStatement) { var localDeclaration = (LocalDeclarationStatementSyntax)statement; SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(localDeclaration); SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (!CanRefactor(localInfo, semanticModel, context.CancellationToken)) { return; } RegisterRefactoring(context, IdentifierName(localInfo.Identifier), localDeclaration, selectedStatements.Count - 1); } else if (kind == SyntaxKind.ExpressionStatement) { var expressionStatement = (ExpressionStatementSyntax)statement; SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(expressionStatement); SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (!CanRefactor(assignmentInfo, assignmentInfo.Left, semanticModel, context.CancellationToken)) { return; } RegisterRefactoring(context, assignmentInfo.Left, expressionStatement, selectedStatements.Count - 1); } }
public async Task ComputeRefactoringAsync(RefactoringContext context, StatementListSelection selectedStatements) { SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(selectedStatements.FirstOrDefault() as LocalDeclarationStatementSyntax); if (!localInfo.Success) { return; } ExpressionSyntax value = localInfo.Value; if (value == null) { return; } if (value.Kind() == SyntaxKind.DefaultExpression) { return; } if (value is LiteralExpressionSyntax) { return; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); var typeSymbol = semanticModel.GetTypeSymbol(localInfo.Type, context.CancellationToken) as INamedTypeSymbol; if (typeSymbol?.Implements(SpecialType.System_IDisposable, allInterfaces: true) != true) { return; } context.RegisterRefactoring( $"Using '{localInfo.IdentifierText}'", cancellationToken => RefactorAsync(context.Document, selectedStatements, cancellationToken), RefactoringIdentifiers.WrapInUsingStatement); }
public static void ComputeRefactoring(RefactoringContext context, StringConcatenationExpressionInfo concatenationInfo) { BinaryExpressionSyntax binaryExpression = concatenationInfo.BinaryExpression; if (binaryExpression.IsParentKind(SyntaxKind.SimpleAssignmentExpression, SyntaxKind.AddAssignmentExpression)) { var assignment = (AssignmentExpressionSyntax)binaryExpression.Parent; if (assignment.IsParentKind(SyntaxKind.ExpressionStatement) && assignment.Right == binaryExpression) { RegisterRefactoring(context, concatenationInfo, (StatementSyntax)assignment.Parent); } } else { SingleLocalDeclarationStatementInfo info = SyntaxInfo.SingleLocalDeclarationStatementInfo(binaryExpression); if (info.Success) { RegisterRefactoring(context, concatenationInfo, info.Statement); } } }
private static void AnalyzeSwitchStatement(SyntaxNodeAnalysisContext context) { var switchStatement = (SwitchStatementSyntax)context.Node; SyntaxList <SwitchSectionSyntax> sections = switchStatement.Sections; if (!sections.Any()) { return; } ExpressionSyntax switchExpression = switchStatement.Expression; SingleLocalDeclarationStatementInfo localInfo = default; string name = GetName(); if (name == null) { return; } ITypeSymbol kindSymbol = context.SemanticModel.GetTypeSymbol(switchExpression, context.CancellationToken); if (kindSymbol?.HasMetadataName(RoslynMetadataNames.Microsoft_CodeAnalysis_CSharp_SyntaxKind) != true) { return; } foreach (SwitchSectionSyntax section in sections) { SwitchLabelSyntax label = section.Labels.SingleOrDefault(shouldThrow: false); if (label == null) { return; } SyntaxKind labelKind = label.Kind(); if (labelKind == SyntaxKind.DefaultSwitchLabel) { continue; } if (labelKind != SyntaxKind.CaseSwitchLabel) { Debug.Assert(labelKind == SyntaxKind.CasePatternSwitchLabel, labelKind.ToString()); return; } var caseLabel = (CaseSwitchLabelSyntax)label; ExpressionSyntax value = caseLabel.Value; if (!value.IsKind(SyntaxKind.SimpleMemberAccessExpression)) { return; } var memberAccess = (MemberAccessExpressionSyntax)value; if (memberAccess.Name is not IdentifierNameSyntax identifierName) { return; } string kindName = identifierName.Identifier.ValueText; if (!_syntaxKindNames.Contains(kindName)) { return; } SyntaxList <StatementSyntax> statements = section.Statements; StatementSyntax statement = statements.FirstOrDefault(); if (statement == null) { return; } if (statement is BlockSyntax block) { statement = block.Statements.FirstOrDefault(); } if (!statement.IsKind(SyntaxKind.LocalDeclarationStatement)) { return; } SingleLocalDeclarationStatementInfo localStatement = SyntaxInfo.SingleLocalDeclarationStatementInfo((LocalDeclarationStatementSyntax)statement); if (!localStatement.Success) { return; } if (localStatement.Value is not CastExpressionSyntax castExpression) { return; } if (castExpression.Expression is not IdentifierNameSyntax localName) { return; } if (name != localName.Identifier.ValueText) { return; } if (!IsFixableSyntaxSymbol(castExpression.Type, kindName, context.SemanticModel, context.CancellationToken)) { return; } } if (localInfo.Success && IsLocalVariableReferenced(context, localInfo, switchStatement)) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UsePatternMatching, switchStatement.SwitchKeyword); string GetName() { switch (switchExpression.Kind()) { case SyntaxKind.IdentifierName: { StatementSyntax previousStatement = switchStatement.PreviousStatement(); if (!previousStatement.IsKind(SyntaxKind.LocalDeclarationStatement)) { return(null); } localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo((LocalDeclarationStatementSyntax)previousStatement); if (!localInfo.Success) { return(null); } if (localInfo.IdentifierText != ((IdentifierNameSyntax)switchExpression).Identifier.ValueText) { return(null); } if (!localInfo.Value.IsKind(SyntaxKind.InvocationExpression)) { return(null); } return(GetName2((InvocationExpressionSyntax)localInfo.Value)); } case SyntaxKind.InvocationExpression: { return(GetName2((InvocationExpressionSyntax)switchExpression)); } default: { return(null); } } }
public static void AnalyzeAsExpression(SyntaxNodeAnalysisContext context) { var asExpression = (BinaryExpressionSyntax)context.Node; AsExpressionInfo asExpressionInfo = SyntaxInfo.AsExpressionInfo(asExpression); if (!asExpressionInfo.Success) { return; } SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(asExpression); if (!localInfo.Success) { return; } if (localInfo.Statement.SpanOrTrailingTriviaContainsDirectives()) { return; } if (!(localInfo.Statement.NextStatement() is IfStatementSyntax ifStatement)) { return; } if (!ifStatement.IsSimpleIf()) { return; } if (ifStatement.SpanOrLeadingTriviaContainsDirectives()) { return; } StatementSyntax statement = ifStatement.SingleNonBlockStatementOrDefault(); if (statement == null) { return; } if (!CSharpFacts.IsJumpStatement(statement.Kind())) { return; } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, NullCheckStyles.EqualsToNull | NullCheckStyles.IsNull); if (!nullCheck.Success) { return; } if (!string.Equals(localInfo.IdentifierText, (nullCheck.Expression as IdentifierNameSyntax)?.Identifier.ValueText, StringComparison.Ordinal)) { return; } context.ReportDiagnostic(DiagnosticDescriptors.UsePatternMatchingInsteadOfAsAndNullCheck, localInfo.Statement); }
private static void AnalyzeLocalDeclarationStatement(SyntaxNodeAnalysisContext context) { var localDeclaration = (LocalDeclarationStatementSyntax)context.Node; if (localDeclaration.ContainsDiagnostics) { return; } if (localDeclaration.SpanOrTrailingTriviaContainsDirectives()) { return; } if (localDeclaration.IsConst) { return; } SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(localDeclaration); if (!localInfo.Success) { return; } SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(localDeclaration.NextStatement()); if (!assignmentInfo.Success) { return; } if (assignmentInfo.Statement.ContainsDiagnostics) { return; } if (assignmentInfo.Statement.SpanOrLeadingTriviaContainsDirectives()) { return; } if (assignmentInfo.Left is not IdentifierNameSyntax identifierName) { return; } string name = identifierName.Identifier.ValueText; if (!string.Equals(localInfo.IdentifierText, name, StringComparison.Ordinal)) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; if (semanticModel.GetSymbol(identifierName, cancellationToken) is not ILocalSymbol localSymbol) { return; } if (!SymbolEqualityComparer.Default.Equals(localSymbol, semanticModel.GetDeclaredSymbol(localInfo.Declarator, cancellationToken))) { return; } ExpressionSyntax value = localInfo.Value; if (value != null) { ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(localInfo.Type, cancellationToken); if (typeSymbol == null) { return; } if (!semanticModel.IsDefaultValue(typeSymbol, value, cancellationToken)) { return; } if (IsReferenced(localSymbol, assignmentInfo.Right, semanticModel, cancellationToken)) { return; } } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveRedundantAssignment, localInfo.Identifier); if (value != null) { DiagnosticHelpers.ReportNode(context, DiagnosticRules.RemoveRedundantAssignmentFadeOut, localInfo.Initializer); DiagnosticHelpers.ReportToken(context, DiagnosticRules.RemoveRedundantAssignmentFadeOut, assignmentInfo.OperatorToken); } DiagnosticHelpers.ReportToken(context, DiagnosticRules.RemoveRedundantAssignmentFadeOut, localDeclaration.SemicolonToken); DiagnosticHelpers.ReportNode(context, DiagnosticRules.RemoveRedundantAssignmentFadeOut, assignmentInfo.Left); }
private static void AnalyzeAsExpression(SyntaxNodeAnalysisContext context) { var asExpression = (BinaryExpressionSyntax)context.Node; AsExpressionInfo asExpressionInfo = SyntaxInfo.AsExpressionInfo(asExpression); if (!asExpressionInfo.Success) { return; } SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(asExpression); if (!localInfo.Success) { return; } if (localInfo.Statement.SpanOrTrailingTriviaContainsDirectives()) { return; } if (!(localInfo.Statement.NextStatement() is IfStatementSyntax ifStatement)) { return; } if (!ifStatement.IsSimpleIf()) { return; } if (ifStatement.SpanOrLeadingTriviaContainsDirectives()) { return; } StatementSyntax statement = ifStatement.SingleNonBlockStatementOrDefault(); if (statement == null) { return; } if (!CSharpFacts.IsJumpStatement(statement.Kind())) { return; } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, NullCheckStyles.EqualsToNull | NullCheckStyles.IsNull); if (!nullCheck.Success) { return; } if (!string.Equals(localInfo.IdentifierText, (nullCheck.Expression as IdentifierNameSyntax)?.Identifier.ValueText, StringComparison.Ordinal)) { return; } if (!localInfo.Type.IsVar) { SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(asExpressionInfo.Type, cancellationToken); if (typeSymbol.IsNullableType()) { return; } if (!SymbolEqualityComparer.Default.Equals(semanticModel.GetTypeSymbol(localInfo.Type, cancellationToken), typeSymbol)) { return; } } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UsePatternMatchingInsteadOfAsAndNullCheck, localInfo.Statement); }
public static void AnalyzeLocalDeclarationStatement(SyntaxNodeAnalysisContext context) { var localDeclarationStatement = (LocalDeclarationStatementSyntax)context.Node; if (localDeclarationStatement.ContainsDiagnostics) { return; } if (localDeclarationStatement.SpanOrTrailingTriviaContainsDirectives()) { return; } SingleLocalDeclarationStatementInfo localDeclarationInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(localDeclarationStatement); if (!localDeclarationInfo.Success) { return; } ExpressionSyntax value = localDeclarationInfo.Value; if (value == null) { return; } SyntaxList <StatementSyntax> statements = SyntaxInfo.StatementListInfo(localDeclarationStatement).Statements; if (!statements.Any()) { return; } int index = statements.IndexOf(localDeclarationStatement); if (index == statements.Count - 1) { return; } StatementSyntax nextStatement = statements[index + 1]; if (nextStatement.ContainsDiagnostics) { return; } switch (nextStatement.Kind()) { case SyntaxKind.ExpressionStatement: { Analyze(context, statements, localDeclarationInfo, index, (ExpressionStatementSyntax)nextStatement); break; } case SyntaxKind.LocalDeclarationStatement: { Analyze(context, statements, localDeclarationInfo, index, (LocalDeclarationStatementSyntax)nextStatement); break; } case SyntaxKind.ReturnStatement: { var returnStatement = (ReturnStatementSyntax)nextStatement; if (!returnStatement.SpanOrLeadingTriviaContainsDirectives()) { ExpressionSyntax expression = returnStatement.Expression; if (expression?.Kind() == SyntaxKind.IdentifierName) { var identifierName = (IdentifierNameSyntax)expression; if (string.Equals(localDeclarationInfo.IdentifierText, identifierName.Identifier.ValueText, StringComparison.Ordinal)) { ReportDiagnostic(context, localDeclarationInfo, expression); } } } break; } case SyntaxKind.ForEachStatement: { if (value.IsSingleLine() && !value.IsKind(SyntaxKind.ArrayInitializerExpression)) { var forEachStatement = (ForEachStatementSyntax)nextStatement; Analyze(context, statements, localDeclarationInfo, forEachStatement.Expression); } break; } case SyntaxKind.SwitchStatement: { if (value.IsSingleLine()) { var switchStatement = (SwitchStatementSyntax)nextStatement; Analyze(context, statements, localDeclarationInfo, switchStatement.Expression); } break; } } }
private static SingleLocalDeclarationStatementInfo GetLocalInfo(StatementSyntax statement) { return((statement.IsKind(SyntaxKind.LocalDeclarationStatement)) ? SyntaxInfo.SingleLocalDeclarationStatementInfo((LocalDeclarationStatementSyntax)statement) : default);
private static Task <Document> UsePatternMatchingAsync( Document document, SwitchStatementSyntax switchStatement, CancellationToken cancellationToken) { SyntaxList <SwitchSectionSyntax> newSections = switchStatement.Sections.Select(section => { if (!(section.Labels.Single() is CaseSwitchLabelSyntax label)) { return(section); } SyntaxList <StatementSyntax> statements = section.Statements; StatementSyntax statement = statements[0]; if (statement is BlockSyntax block) { statement = block.Statements.FirstOrDefault(); } SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo((LocalDeclarationStatementSyntax)statement); var castExpression = (CastExpressionSyntax)localInfo.Value; CasePatternSwitchLabelSyntax newLabel = CasePatternSwitchLabel( DeclarationPattern( castExpression.Type, SingleVariableDesignation(localInfo.Identifier)), label.ColonToken); SwitchSectionSyntax newSection = section.RemoveStatement(localInfo.Statement); newSection = newSection.WithLabels(newSection.Labels.ReplaceAt(0, newLabel)); return(newSection.WithFormatterAnnotation()); }) .ToSyntaxList(); ExpressionSyntax expression = switchStatement.Expression; ExpressionSyntax newExpression = expression; LocalDeclarationStatementSyntax localDeclaration = null; if (expression.IsKind(SyntaxKind.InvocationExpression)) { SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(expression); newExpression = invocationInfo.Expression; } else { localDeclaration = (LocalDeclarationStatementSyntax)switchStatement.PreviousStatement(); SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(localDeclaration); SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(localInfo.Value); newExpression = invocationInfo.Expression; } SwitchStatementSyntax newSwitchStatement = switchStatement .WithExpression(newExpression.WithTriviaFrom(expression)) .WithSections(newSections); if (localDeclaration != null) { StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(switchStatement); newSwitchStatement = newSwitchStatement.WithLeadingTrivia(localDeclaration.GetLeadingTrivia()); SyntaxList <StatementSyntax> newStatements = statementsInfo.Statements .Replace(switchStatement, newSwitchStatement) .RemoveAt(statementsInfo.IndexOf(localDeclaration)); return(document.ReplaceStatementsAsync(statementsInfo, newStatements, cancellationToken)); } else { return(document.ReplaceNodeAsync(switchStatement, newSwitchStatement, cancellationToken)); } }
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); } }
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)))); } }
public static async Task ComputeRefactoringAsync(RefactoringContext context, ConditionalExpressionSyntax conditionalExpression) { ExpressionSyntax expression = conditionalExpression.WalkUpParentheses(); SyntaxNode parent = expression.Parent; if (parent.IsKind(SyntaxKind.ReturnStatement, SyntaxKind.YieldReturnStatement)) { var statement = (StatementSyntax)parent; RegisterRefactoring(context, conditionalExpression, statement); if (IsRecursive()) { RegisterRefactoring(context, conditionalExpression, statement, recursive: true); } } else if (parent is AssignmentExpressionSyntax assignment) { if (assignment.Parent is ExpressionStatementSyntax expressionStatement) { RegisterRefactoring(context, conditionalExpression, expressionStatement); if (IsRecursive()) { RegisterRefactoring(context, conditionalExpression, expressionStatement, recursive: true); } } } else { SingleLocalDeclarationStatementInfo localDeclarationInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(expression); if (localDeclarationInfo.Success) { TypeSyntax type = localDeclarationInfo.Type; SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (!type.IsVar || semanticModel.GetTypeSymbol(type, context.CancellationToken)?.SupportsExplicitDeclaration() == true) { LocalDeclarationStatementSyntax statement = localDeclarationInfo.Statement; RegisterRefactoring(context, conditionalExpression, statement, semanticModel); if (IsRecursive()) { RegisterRefactoring(context, conditionalExpression, statement, semanticModel, recursive: true); } } } } bool IsRecursive() { return(conditionalExpression .WhenFalse .WalkDownParentheses() .IsKind(SyntaxKind.ConditionalExpression)); } }
public static void AnalyzeLocalDeclarationStatement(SyntaxNodeAnalysisContext context) { var localDeclarationStatement = (LocalDeclarationStatementSyntax)context.Node; if (localDeclarationStatement.ContainsDiagnostics) { return; } if (localDeclarationStatement.SpanOrTrailingTriviaContainsDirectives()) { return; } SingleLocalDeclarationStatementInfo localDeclarationInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(localDeclarationStatement); if (!localDeclarationInfo.Success) { return; } ExpressionSyntax value = localDeclarationInfo.Value; if (value == null) { return; } SyntaxList <StatementSyntax> statements = SyntaxInfo.StatementListInfo(localDeclarationStatement).Statements; if (!statements.Any()) { return; } int index = statements.IndexOf(localDeclarationStatement); if (index == statements.Count - 1) { return; } StatementSyntax nextStatement = statements[index + 1]; if (nextStatement.ContainsDiagnostics) { return; } switch (nextStatement.Kind()) { case SyntaxKind.ExpressionStatement: { Analyze(context, statements, localDeclarationInfo, index, (ExpressionStatementSyntax)nextStatement); break; } case SyntaxKind.LocalDeclarationStatement: { Analyze(context, statements, localDeclarationInfo, index, (LocalDeclarationStatementSyntax)nextStatement); break; } case SyntaxKind.ReturnStatement: { var returnStatement = (ReturnStatementSyntax)nextStatement; if (!returnStatement.SpanOrLeadingTriviaContainsDirectives()) { ExpressionSyntax expression = returnStatement.Expression; if (expression?.Kind() == SyntaxKind.IdentifierName) { var identifierName = (IdentifierNameSyntax)expression; if (string.Equals(localDeclarationInfo.IdentifierText, identifierName.Identifier.ValueText, StringComparison.Ordinal)) { ReportDiagnostic(context, localDeclarationInfo, expression); } } } break; } case SyntaxKind.YieldReturnStatement: { var yieldStatement = (YieldStatementSyntax)nextStatement; if (index == statements.Count - 2 && !yieldStatement.SpanOrLeadingTriviaContainsDirectives()) { ExpressionSyntax expression = yieldStatement.Expression; if (expression?.Kind() == SyntaxKind.IdentifierName) { var identifierName = (IdentifierNameSyntax)expression; if (string.Equals(localDeclarationInfo.IdentifierText, identifierName.Identifier.ValueText, StringComparison.Ordinal)) { ReportDiagnostic(context, localDeclarationInfo, expression); } } } break; } case SyntaxKind.ForEachStatement: { if (value.WalkDownParentheses().IsKind(SyntaxKind.AwaitExpression)) { return; } if (!value.IsSingleLine()) { return; } if (value.IsKind(SyntaxKind.ArrayInitializerExpression)) { return; } var forEachStatement = (ForEachStatementSyntax)nextStatement; ISymbol localSymbol = GetLocalSymbol(localDeclarationInfo, forEachStatement.Expression, context.SemanticModel, context.CancellationToken); if (localSymbol?.IsErrorType() != false) { return; } ContainsLocalOrParameterReferenceWalker walker = ContainsLocalOrParameterReferenceWalker.GetInstance(localSymbol, context.SemanticModel, context.CancellationToken); walker.Visit(forEachStatement.Statement); if (!walker.Result && index < statements.Count - 2) { walker.VisitList(statements, index + 2); } if (ContainsLocalOrParameterReferenceWalker.GetResultAndFree(walker)) { return; } ReportDiagnostic(context, localDeclarationInfo, forEachStatement.Expression); break; } case SyntaxKind.SwitchStatement: { if (value.WalkDownParentheses().IsKind(SyntaxKind.AwaitExpression)) { return; } if (!value.IsSingleLine()) { return; } var switchStatement = (SwitchStatementSyntax)nextStatement; ISymbol localSymbol = GetLocalSymbol(localDeclarationInfo, switchStatement.Expression, context.SemanticModel, context.CancellationToken); if (localSymbol?.IsErrorType() != false) { return; } ContainsLocalOrParameterReferenceWalker walker = ContainsLocalOrParameterReferenceWalker.GetInstance(localSymbol, context.SemanticModel, context.CancellationToken); walker.VisitList(switchStatement.Sections); if (!walker.Result && index < statements.Count - 2) { walker.VisitList(statements, index + 2); } if (ContainsLocalOrParameterReferenceWalker.GetResultAndFree(walker)) { return; } ReportDiagnostic(context, localDeclarationInfo, switchStatement.Expression); break; } } }
public static void AnalyzeLocalDeclarationStatement(SyntaxNodeAnalysisContext context) { var localDeclaration = (LocalDeclarationStatementSyntax)context.Node; if (localDeclaration.ContainsDiagnostics) { return; } if (localDeclaration.SpanOrTrailingTriviaContainsDirectives()) { return; } if (localDeclaration.IsConst) { return; } SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(localDeclaration); if (!localInfo.Success) { return; } SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(localDeclaration.NextStatementOrDefault()); if (!assignmentInfo.Success) { return; } if (assignmentInfo.Statement.ContainsDiagnostics) { return; } if (assignmentInfo.Statement.SpanOrLeadingTriviaContainsDirectives()) { return; } if (!(assignmentInfo.Left is IdentifierNameSyntax identifierName)) { return; } string name = identifierName.Identifier.ValueText; if (!string.Equals(localInfo.IdentifierText, name, StringComparison.Ordinal)) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; var localSymbol = semanticModel.GetSymbol(identifierName, cancellationToken) as ILocalSymbol; if (localSymbol == null) { return; } if (!localSymbol.Equals(semanticModel.GetDeclaredSymbol(localInfo.Declarator, cancellationToken))) { return; } EqualsValueClauseSyntax initializer = localInfo.Initializer; ExpressionSyntax value = initializer?.Value; if (value != null) { ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(localInfo.Type, cancellationToken); if (typeSymbol == null) { return; } if (!semanticModel.IsDefaultValue(typeSymbol, value, cancellationToken)) { return; } if (IsReferenced(localSymbol, assignmentInfo.Right, semanticModel, cancellationToken)) { return; } } context.ReportDiagnostic(DiagnosticDescriptors.MergeLocalDeclarationWithAssignment, localInfo.Identifier); if (value != null) { context.ReportNode(DiagnosticDescriptors.MergeLocalDeclarationWithAssignmentFadeOut, initializer); context.ReportToken(DiagnosticDescriptors.MergeLocalDeclarationWithAssignmentFadeOut, assignmentInfo.OperatorToken); } context.ReportToken(DiagnosticDescriptors.MergeLocalDeclarationWithAssignmentFadeOut, localDeclaration.SemicolonToken); context.ReportNode(DiagnosticDescriptors.MergeLocalDeclarationWithAssignmentFadeOut, assignmentInfo.Left); }