private static Task <Document> RefactorAsync( Document document, LocalDeclarationStatementSyntax localDeclaration, CancellationToken cancellationToken) { VariableDeclaratorSyntax variableDeclarator = localDeclaration .Declaration .Variables .Single(); ExpressionSyntax expression = variableDeclarator .Initializer .Value .WalkDownParentheses(); AsExpressionInfo asExpressionInfo = SyntaxInfo.AsExpressionInfo(expression); PrefixUnaryExpressionSyntax newCondition = LogicalNotExpression( ParenthesizedExpression( IsPatternExpression( asExpressionInfo.Expression, DeclarationPattern( asExpressionInfo.Type, SingleVariableDesignation(variableDeclarator.Identifier))))); StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(localDeclaration); int index = statementsInfo.IndexOf(localDeclaration); var ifStatement = (IfStatementSyntax)statementsInfo[index + 1]; SyntaxTriviaList leadingTrivia = statementsInfo.Parent .DescendantTrivia(TextSpan.FromBounds(localDeclaration.SpanStart, ifStatement.SpanStart)) .ToSyntaxTriviaList() .EmptyIfWhitespace(); leadingTrivia = localDeclaration.GetLeadingTrivia().AddRange(leadingTrivia); StatementSyntax newStatement = ifStatement.Statement; if (ifStatement.SingleNonBlockStatementOrDefault() is ReturnStatementSyntax returnStatement && returnStatement.Expression?.WalkDownParentheses() is IdentifierNameSyntax identifierName && string.Equals(identifierName.Identifier.ValueText, variableDeclarator.Identifier.ValueText, System.StringComparison.Ordinal)) { newStatement = newStatement.ReplaceNode(returnStatement.Expression, NullLiteralExpression().WithTriviaFrom(returnStatement.Expression)); } IfStatementSyntax newIfStatement = ifStatement .WithCondition(newCondition.WithTriviaFrom(ifStatement.Condition)) .WithStatement(newStatement) .WithLeadingTrivia(leadingTrivia) .WithFormatterAnnotation(); SyntaxList <StatementSyntax> newStatements = statementsInfo.Statements.ReplaceRange(index, 2, newIfStatement); return(document.ReplaceStatementsAsync(statementsInfo, newStatements, cancellationToken)); }
public static async Task <Document> RefactorAsync( Document document, WhileStatementSyntax whileStatement, CancellationToken cancellationToken) { StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(whileStatement); if (statementsInfo.Success) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); int index = FindLocalDeclarationStatementIndex( whileStatement, statementsInfo.Statements, startIndex: 0, count: statementsInfo.IndexOf(whileStatement), mustBeReferencedInsideWhileStatement: true, semanticModel: semanticModel, cancellationToken: cancellationToken); if (index >= 0) { List <LocalDeclarationStatementSyntax> localDeclarations = statementsInfo .Statements .Skip(index) .Take(statementsInfo.IndexOf(whileStatement) - index) .Cast <LocalDeclarationStatementSyntax>() .ToList(); return(await RefactorAsync(document, whileStatement, localDeclarations, cancellationToken).ConfigureAwait(false)); } } return(await document.ReplaceNodeAsync( whileStatement, SyntaxRefactorings.ConvertWhileStatementToForStatement(whileStatement), cancellationToken) .ConfigureAwait(false)); }
private static Task <Document> RefactorAsync( Document document, LocalDeclarationStatementSyntax localDeclaration, CancellationToken cancellationToken) { VariableDeclaratorSyntax variableDeclarator = localDeclaration .Declaration .Variables .Single(); ExpressionSyntax expression = variableDeclarator .Initializer .Value .WalkDownParentheses(); AsExpressionInfo asExpressionInfo = SyntaxInfo.AsExpressionInfo(expression); PrefixUnaryExpressionSyntax newCondition = LogicalNotExpression( ParenthesizedExpression( IsPatternExpression( asExpressionInfo.Expression, DeclarationPattern( asExpressionInfo.Type, SingleVariableDesignation(variableDeclarator.Identifier))))); StatementListInfo statements = SyntaxInfo.StatementListInfo(localDeclaration); int index = statements.IndexOf(localDeclaration); var ifStatement = (IfStatementSyntax)statements[index + 1]; SyntaxTriviaList leadingTrivia = localDeclaration .DescendantTrivia(TextSpan.FromBounds(localDeclaration.SpanStart, ifStatement.SpanStart)) .ToSyntaxTriviaList() .EmptyIfWhitespace(); leadingTrivia = localDeclaration.GetLeadingTrivia().AddRange(leadingTrivia); IfStatementSyntax newIfStatement = ifStatement .WithCondition(newCondition.WithTriviaFrom(ifStatement.Condition)) .WithLeadingTrivia(leadingTrivia); StatementListInfo newStatements = statements.RemoveAt(index).ReplaceAt(index, newIfStatement); return(document.ReplaceStatementsAsync(statements, newStatements, cancellationToken)); }
private static Task <Document> RefactorAsync( Document document, SingleLocalDeclarationStatementInfo localInfo, TypeSyntax type, StatementListInfo statementsInfo, CancellationToken cancellationToken) { LocalDeclarationStatementSyntax localStatement = localInfo.Statement; int index = statementsInfo.IndexOf(localStatement); VariableDeclaratorSyntax declarator = localInfo.Declarator; VariableDeclaratorSyntax newDeclarator = declarator.WithInitializer(null); VariableDeclarationSyntax newDeclaration = localInfo.Declaration.ReplaceNode(declarator, newDeclarator); if (type != null) { newDeclaration = newDeclaration.WithType(type.WithTriviaFrom(newDeclaration.Type)); } LocalDeclarationStatementSyntax newLocalStatement = localStatement .WithDeclaration(newDeclaration) .WithTrailingTrivia(NewLine()) .WithFormatterAnnotation(); ExpressionStatementSyntax assignmentStatement = SimpleAssignmentStatement(IdentifierName(localInfo.Identifier), localInfo.Initializer.Value) .WithTrailingTrivia(localStatement.GetTrailingTrivia()) .WithFormatterAnnotation(); StatementListInfo newStatementsInfo = statementsInfo .Insert(index + 1, assignmentStatement) .ReplaceAt(index, newLocalStatement); return(document.ReplaceStatementsAsync(statementsInfo, newStatementsInfo, cancellationToken)); }
private static bool IsLocalVariableReferenced( SyntaxNodeAnalysisContext context, SingleLocalDeclarationStatementInfo localInfo, SwitchStatementSyntax switchStatement) { ISymbol localSymbol = context.SemanticModel.GetDeclaredSymbol(localInfo.Declarator, context.CancellationToken); if (localSymbol.IsKind(SymbolKind.Local)) { ContainsLocalOrParameterReferenceWalker walker = ContainsLocalOrParameterReferenceWalker.GetInstance(localSymbol, context.SemanticModel, context.CancellationToken); walker.VisitList(switchStatement.Sections); if (!walker.Result) { StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(switchStatement); if (statementsInfo.Success) { int index = statementsInfo.IndexOf(switchStatement); if (index < statementsInfo.Count - 1) { walker.VisitList(statementsInfo.Statements, index + 1); } } } bool isReferenced = walker.Result; ContainsLocalOrParameterReferenceWalker.Free(walker); return(isReferenced); } return(false); }
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 async Task <StatementListInfo> RefactorAsync <TStatement>( Document document, TStatement statement, StatementListInfo statementsInfo, Func <TStatement, TStatement> createNewStatement, int count, bool removeReturnStatement, CancellationToken cancellationToken) where TStatement : StatementSyntax { int statementIndex = statementsInfo.IndexOf(statement); var returnStatement = (ReturnStatementSyntax)statementsInfo[statementIndex + 1]; ExpressionSyntax returnExpression = returnStatement.Expression; ExpressionSyntax newReturnExpression = null; SyntaxTriviaList newTrailingTrivia = default; SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); ISymbol symbol = semanticModel.GetSymbol(returnExpression, cancellationToken); if (symbol.Kind == SymbolKind.Local && statementIndex > 0 && statementsInfo[statementIndex - 1] is LocalDeclarationStatementSyntax localDeclarationStatement && !localDeclarationStatement.ContainsDiagnostics && !localDeclarationStatement.SpanOrTrailingTriviaContainsDirectives() && !statement.GetLeadingTrivia().Any(f => f.IsDirective)) { SeparatedSyntaxList <VariableDeclaratorSyntax> declarators = localDeclarationStatement.Declaration.Variables; VariableDeclaratorSyntax declarator = declarators.FirstOrDefault(f => semanticModel.GetDeclaredSymbol(f, cancellationToken)?.Equals(symbol) == true); if (declarator != null) { ExpressionSyntax value = declarator.Initializer?.Value; if (removeReturnStatement || value != null) { IEnumerable <ReferencedSymbol> referencedSymbols = await SymbolFinder.FindReferencesAsync(symbol, document.Solution(), cancellationToken).ConfigureAwait(false); if (referencedSymbols.First().Locations.Count() == count + 1) { newReturnExpression = value; if (declarators.Count == 1) { if (!removeReturnStatement && returnStatement.GetTrailingTrivia().IsEmptyOrWhitespace()) { SyntaxTriviaList trailingTrivia = localDeclarationStatement.GetTrailingTrivia(); if (trailingTrivia .SkipWhile(f => f.IsWhitespaceTrivia()) .FirstOrDefault() .IsKind(SyntaxKind.SingleLineCommentTrivia)) { newTrailingTrivia = trailingTrivia; } } SyntaxRemoveOptions removeOptions = SyntaxRefactorings.GetRemoveOptions(localDeclarationStatement); if (newTrailingTrivia.Any()) { removeOptions &= ~SyntaxRemoveOptions.KeepTrailingTrivia; } statementsInfo = statementsInfo.RemoveNode(localDeclarationStatement, removeOptions); statementIndex--; } else { statementsInfo = statementsInfo.ReplaceNode(localDeclarationStatement, localDeclarationStatement.RemoveNode(declarator, SyntaxRefactorings.GetRemoveOptions(declarator))); } returnStatement = (ReturnStatementSyntax)statementsInfo[statementIndex + 1]; } } } } if (removeReturnStatement) { statementsInfo = statementsInfo.RemoveNode(returnStatement, SyntaxRefactorings.GetRemoveOptions(returnStatement)); } else if (newReturnExpression != null) { ReturnStatementSyntax newReturnStatement = returnStatement.WithExpression(newReturnExpression.WithTriviaFrom(returnExpression)); if (newTrailingTrivia.Any()) { newReturnStatement = newReturnStatement.WithTrailingTrivia(newTrailingTrivia); } statementsInfo = statementsInfo.ReplaceNode(returnStatement, newReturnStatement); } StatementSyntax oldNode = statementsInfo[statementIndex]; TStatement newNode = createNewStatement((TStatement)oldNode).WithFormatterAnnotation(); return(statementsInfo.ReplaceNode(oldNode, newNode)); }
private static void AnalyzeSimpleAssignment(SyntaxNodeAnalysisContext context) { if (context.Node.ContainsDiagnostics) { return; } if (context.Node.SpanOrTrailingTriviaContainsDirectives()) { return; } var assignment = (AssignmentExpressionSyntax)context.Node; SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(assignment); if (!assignmentInfo.Success) { return; } if (assignmentInfo.Left is not IdentifierNameSyntax identifierName) { return; } StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(assignmentInfo.Statement); if (!statementsInfo.Success) { return; } int index = statementsInfo.IndexOf(assignmentInfo.Statement); if (index == statementsInfo.Count - 1) { return; } if (index > 0) { StatementSyntax previousStatement = statementsInfo[index - 1]; SimpleAssignmentStatementInfo assignmentInfo2 = SyntaxInfo.SimpleAssignmentStatementInfo(previousStatement); if (assignmentInfo2.Success && assignmentInfo2.Left is IdentifierNameSyntax identifierName2 && string.Equals(identifierName.Identifier.ValueText, identifierName2.Identifier.ValueText, StringComparison.Ordinal)) { return; } } StatementSyntax nextStatement = statementsInfo[index + 1]; if (nextStatement.SpanOrLeadingTriviaContainsDirectives()) { return; } if (nextStatement is not ReturnStatementSyntax returnStatement) { return; } if (returnStatement.Expression?.WalkDownParentheses() is not IdentifierNameSyntax identifierName3) { return; } if (!string.Equals(identifierName.Identifier.ValueText, identifierName3.Identifier.ValueText, StringComparison.Ordinal)) { return; } ISymbol symbol = context.SemanticModel.GetSymbol(identifierName, context.CancellationToken); switch (symbol?.Kind) { case SymbolKind.Local: { break; } case SymbolKind.Parameter: { if (((IParameterSymbol)symbol).RefKind != RefKind.None) { return; } break; } default: { return; } } if (IsAssignedInsideAnonymousFunctionButDeclaredOutsideOfIt()) { return; } bool result; RemoveRedundantAssignmentWalker walker = null; try { walker = RemoveRedundantAssignmentWalker.GetInstance(); walker.Symbol = symbol; walker.SemanticModel = context.SemanticModel; walker.CancellationToken = context.CancellationToken; walker.Result = false; walker.Visit(assignmentInfo.Right); result = walker.Result; } finally { if (walker != null) { RemoveRedundantAssignmentWalker.Free(walker); } } if (result) { return; } if (IsDeclaredInTryStatementOrCatchClauseAndReferencedInFinallyClause(context, assignmentInfo.Statement, symbol)) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveRedundantAssignment, assignment); bool IsAssignedInsideAnonymousFunctionButDeclaredOutsideOfIt() { SyntaxNode declaringSyntax = null; SyntaxNode n = assignment.Parent; do { if (CSharpFacts.IsAnonymousFunctionExpression(n.Kind())) { if (declaringSyntax == null) { declaringSyntax = symbol.GetSyntaxOrDefault(); Debug.Assert(declaringSyntax != null, ""); if (declaringSyntax == null) { break; } SyntaxDebug.Assert(declaringSyntax.IsKind(SyntaxKind.VariableDeclarator, SyntaxKind.Parameter), declaringSyntax); } SyntaxNode n2 = declaringSyntax.Parent; do { if (CSharpFacts.IsAnonymousFunctionExpression(n2.Kind())) { return(!object.ReferenceEquals(n, n2)); } if (n2 is MemberDeclarationSyntax) { break; } n2 = n2.Parent; }while (n2 != null); return(true); } else if (n is MemberDeclarationSyntax) { break; } n = n.Parent; }while (n != null); return(false); } }
public static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context) { if (context.Node.ContainsDiagnostics) { return; } var ifStatement = (IfStatementSyntax)context.Node; if (ifStatement.IsSimpleIf()) { return; } StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(ifStatement); if (!statementsInfo.Success) { return; } int index = statementsInfo.IndexOf(ifStatement); ReturnStatementSyntax returnStatement = FindReturnStatementBelow(statementsInfo.Statements, index); if (returnStatement == null) { return; } if (returnStatement.ContainsDiagnostics) { return; } ExpressionSyntax expression = returnStatement.Expression; if (expression == null) { return; } if (ifStatement.SpanOrTrailingTriviaContainsDirectives()) { return; } if (returnStatement.SpanOrLeadingTriviaContainsDirectives()) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; ISymbol symbol = semanticModel.GetSymbol(expression, cancellationToken); if (!IsLocalDeclaredInScopeOrNonRefOrOutParameterOfEnclosingSymbol(symbol, statementsInfo.Parent, semanticModel, cancellationToken)) { return; } foreach (IfStatementOrElseClause ifOrElse in ifStatement.AsCascade()) { if (!IsSymbolAssignedInLastStatement(ifOrElse, symbol, semanticModel, cancellationToken)) { return; } } context.ReportDiagnostic(DiagnosticDescriptors.UseReturnInsteadOfAssignment, ifStatement); }
public static void AnalyzeSwitchStatement(SyntaxNodeAnalysisContext context) { if (context.Node.ContainsDiagnostics) { return; } var switchStatement = (SwitchStatementSyntax)context.Node; StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(switchStatement); if (!statementsInfo.Success) { return; } int index = statementsInfo.IndexOf(switchStatement); ReturnStatementSyntax returnStatement = FindReturnStatementBelow(statementsInfo.Statements, index); if (returnStatement == null) { return; } ExpressionSyntax expression = returnStatement.Expression; if (expression == null) { return; } if (expression.ContainsDiagnostics) { return; } if (switchStatement.SpanOrTrailingTriviaContainsDirectives()) { return; } if (returnStatement.SpanOrLeadingTriviaContainsDirectives()) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; ISymbol symbol = semanticModel.GetSymbol(expression, cancellationToken); if (!IsLocalDeclaredInScopeOrNonRefOrOutParameterOfEnclosingSymbol(symbol, statementsInfo.Parent, semanticModel, cancellationToken)) { return; } if (!switchStatement .Sections .All(section => IsValueAssignedInLastStatement(section, symbol, semanticModel, cancellationToken))) { return; } context.ReportDiagnostic(DiagnosticDescriptors.UseReturnInsteadOfAssignment, switchStatement); }
internal static void AnalyzeSimpleAssignment(SyntaxNodeAnalysisContext context) { if (context.Node.ContainsDiagnostics) { return; } if (context.Node.SpanOrTrailingTriviaContainsDirectives()) { return; } var assignment = (AssignmentExpressionSyntax)context.Node; SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(assignment); if (!assignmentInfo.Success) { return; } if (!(assignmentInfo.Left is IdentifierNameSyntax identifierName)) { return; } StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(assignmentInfo.Statement); if (!statementsInfo.Success) { return; } int index = statementsInfo.IndexOf(assignmentInfo.Statement); if (index == statementsInfo.Count - 1) { return; } if (index > 0) { StatementSyntax previousStatement = statementsInfo[index - 1]; SimpleAssignmentStatementInfo assignmentInfo2 = SyntaxInfo.SimpleAssignmentStatementInfo(previousStatement); if (assignmentInfo2.Success && assignmentInfo2.Left is IdentifierNameSyntax identifierName2 && string.Equals(identifierName.Identifier.ValueText, identifierName2.Identifier.ValueText, StringComparison.Ordinal)) { return; } } StatementSyntax nextStatement = statementsInfo[index + 1]; if (nextStatement.SpanOrLeadingTriviaContainsDirectives()) { return; } if (!(nextStatement is ReturnStatementSyntax returnStatement)) { return; } if (!(returnStatement.Expression?.WalkDownParentheses() is IdentifierNameSyntax identifierName3)) { return; } if (!string.Equals(identifierName.Identifier.ValueText, identifierName3.Identifier.ValueText, StringComparison.Ordinal)) { return; } ISymbol symbol = context.SemanticModel.GetSymbol(identifierName, context.CancellationToken); switch (symbol?.Kind) { case SymbolKind.Local: { break; } case SymbolKind.Parameter: { if (((IParameterSymbol)symbol).RefKind != RefKind.None) { return; } break; } default: { return; } } RemoveRedundantAssignmentWalker walker = RemoveRedundantAssignmentWalker.GetInstance(); walker.Symbol = symbol; walker.SemanticModel = context.SemanticModel; walker.CancellationToken = context.CancellationToken; walker.Result = false; walker.Visit(assignmentInfo.Right); bool result = walker.Result; RemoveRedundantAssignmentWalker.Free(walker); if (result) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.RemoveRedundantAssignment, assignment); }
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); } } }
private static async Task <StatementListInfo> RefactorAsync <TStatement>( Document document, TStatement statement, StatementListInfo statementsInfo, Func <TStatement, TStatement> createNewStatement, int count, bool removeReturnStatement, CancellationToken cancellationToken) where TStatement : StatementSyntax { int index = statementsInfo.IndexOf(statement); var returnStatement = (ReturnStatementSyntax)statementsInfo[index + 1]; ExpressionSyntax expression = returnStatement.Expression; ExpressionSyntax newExpression = null; SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); ISymbol symbol = semanticModel.GetSymbol(expression, cancellationToken); if (symbol.Kind == SymbolKind.Local && index > 0) { var localDeclarationStatement = statementsInfo[index - 1] as LocalDeclarationStatementSyntax; if (localDeclarationStatement?.ContainsDiagnostics == false && !localDeclarationStatement.SpanOrTrailingTriviaContainsDirectives() && !statement.GetLeadingTrivia().Any(f => f.IsDirective)) { SeparatedSyntaxList <VariableDeclaratorSyntax> declarators = localDeclarationStatement.Declaration.Variables; VariableDeclaratorSyntax declarator = declarators.FirstOrDefault(f => semanticModel.GetDeclaredSymbol(f, cancellationToken)?.Equals(symbol) == true); if (declarator != null) { ExpressionSyntax value = declarator.Initializer?.Value; if (removeReturnStatement || value != null) { IEnumerable <ReferencedSymbol> referencedSymbols = await SymbolFinder.FindReferencesAsync(symbol, document.Solution(), cancellationToken).ConfigureAwait(false); if (referencedSymbols.First().Locations.Count() == count + 1) { newExpression = value; if (declarators.Count == 1) { statementsInfo = statementsInfo.RemoveNode(localDeclarationStatement, SyntaxRemover.GetRemoveOptions(localDeclarationStatement)); index--; } else { statementsInfo = statementsInfo.ReplaceNode(localDeclarationStatement, localDeclarationStatement.RemoveNode(declarator, SyntaxRemover.GetRemoveOptions(declarator))); } returnStatement = (ReturnStatementSyntax)statementsInfo[index + 1]; } } } } } if (removeReturnStatement) { statementsInfo = statementsInfo.RemoveNode(returnStatement, SyntaxRemover.GetRemoveOptions(returnStatement)); } else if (newExpression != null) { statementsInfo = statementsInfo.ReplaceNode(returnStatement, returnStatement.WithExpression(newExpression.WithTriviaFrom(expression))); } StatementSyntax oldNode = statementsInfo[index]; TStatement newNode = createNewStatement((TStatement)oldNode).WithFormatterAnnotation(); return(statementsInfo.ReplaceNode(oldNode, newNode)); }
internal static void AnalyzeSimpleAssignment(SyntaxNodeAnalysisContext context) { if (context.Node.ContainsDiagnostics) { return; } if (context.Node.SpanOrTrailingTriviaContainsDirectives()) { return; } var assignment = (AssignmentExpressionSyntax)context.Node; SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(assignment); if (!assignmentInfo.Success) { return; } if (!(assignmentInfo.Left is IdentifierNameSyntax identifierName)) { return; } StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(assignmentInfo.Statement); if (!statementsInfo.Success) { return; } int index = statementsInfo.IndexOf(assignmentInfo.Statement); if (index == statementsInfo.Count - 1) { return; } if (index > 0) { StatementSyntax previousStatement = statementsInfo[index - 1]; SimpleAssignmentStatementInfo assignmentInfo2 = SyntaxInfo.SimpleAssignmentStatementInfo(previousStatement); if (assignmentInfo2.Success && assignmentInfo2.Left is IdentifierNameSyntax identifierName2 && string.Equals(identifierName.Identifier.ValueText, identifierName2.Identifier.ValueText, StringComparison.Ordinal)) { return; } } StatementSyntax nextStatement = statementsInfo[index + 1]; if (nextStatement.SpanOrLeadingTriviaContainsDirectives()) { return; } if (!(nextStatement is ReturnStatementSyntax returnStatement)) { return; } if (!(returnStatement.Expression?.WalkDownParentheses() is IdentifierNameSyntax identifierName3)) { return; } if (!string.Equals(identifierName.Identifier.ValueText, identifierName3.Identifier.ValueText, StringComparison.Ordinal)) { return; } ISymbol symbol = context.SemanticModel.GetSymbol(identifierName, context.CancellationToken); if (symbol == null) { return; } if (!IsFixableSymbol(symbol)) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.RemoveRedundantAssignment, assignment); }
public static async Task <Document> RefactorAsync( Document document, StatementSyntax statement, CancellationToken cancellationToken) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(statement); int index = statementsInfo.IndexOf(statement); switch (statement.Kind()) { case SyntaxKind.IfStatement: { var ifStatement = (IfStatementSyntax)statement; int count = 0; bool endsWithElse = false; foreach (IfStatementOrElseClause ifOrElse in ifStatement.AsCascade()) { count++; endsWithElse = ifOrElse.IsElse; } StatementListInfo newStatementsInfo = await RefactorAsync( document, statementsInfo, ifStatement, CreateNewIfStatement, index, count, endsWithElse, semanticModel, cancellationToken).ConfigureAwait(false); return(await document.ReplaceNodeAsync(statementsInfo.Parent, newStatementsInfo.Parent, cancellationToken).ConfigureAwait(false)); } case SyntaxKind.SwitchStatement: { var switchStatement = (SwitchStatementSyntax)statement; StatementListInfo newStatementsInfo = await RefactorAsync( document, statementsInfo, switchStatement, CreateNewSwitchStatement, index, switchStatement.Sections.Count, switchStatement.Sections.Any(f => f.ContainsDefaultLabel()), semanticModel, cancellationToken).ConfigureAwait(false); return(await document.ReplaceNodeAsync(statementsInfo.Parent, newStatementsInfo.Parent, cancellationToken).ConfigureAwait(false)); } } Debug.Fail(statement.Kind().ToString()); return(document); }
public static async Task <Document> RefactorAsync( Document document, StatementSyntax statement, CancellationToken cancellationToken) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(statement); int index = statementsInfo.IndexOf(statement); switch (statement.Kind()) { case SyntaxKind.IfStatement: { var ifStatement = (IfStatementSyntax)statement; IEnumerable <ExpressionStatementSyntax> expressionStatements = ifStatement .AsCascade() .Select(ifOrElse => (ExpressionStatementSyntax)GetLastStatementOrDefault(ifOrElse.Statement)); IfStatementSyntax newIfStatement = ifStatement.ReplaceNodes( expressionStatements, (f, _) => { var assignment = (AssignmentExpressionSyntax)f.Expression; return(ReturnStatement(assignment.Right).WithTriviaFrom(f)); }); int count = 0; bool endsWithElse = false; foreach (IfStatementOrElseClause ifOrElse in ifStatement.AsCascade()) { count++; endsWithElse = ifOrElse.IsElse; } StatementListInfo newStatementsInfo = await RefactorAsync( document, statementsInfo, ifStatement, newIfStatement, index, count, endsWithElse, semanticModel, cancellationToken).ConfigureAwait(false); return(await document.ReplaceNodeAsync(statementsInfo.Parent, newStatementsInfo.Parent, cancellationToken).ConfigureAwait(false)); } case SyntaxKind.SwitchStatement: { var switchStatement = (SwitchStatementSyntax)statement; SyntaxList <SwitchSectionSyntax> newSections = switchStatement .Sections .Select(CreateNewSection) .ToSyntaxList(); SwitchStatementSyntax newSwitchStatement = switchStatement.WithSections(newSections); StatementListInfo newStatementsInfo = await RefactorAsync( document, statementsInfo, switchStatement, newSwitchStatement, index, switchStatement.Sections.Count, switchStatement.Sections.Any(f => f.ContainsDefaultLabel()), semanticModel, cancellationToken).ConfigureAwait(false); return(await document.ReplaceNodeAsync(statementsInfo.Parent, newStatementsInfo.Parent, cancellationToken).ConfigureAwait(false)); } } Debug.Fail(statement.Kind().ToString()); return(document); }